Coverage Report

Created: 2024-09-11 07:09

/src/spirv-tools/source/opt/cfg.h
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) 2017 Google Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
15
#ifndef SOURCE_OPT_CFG_H_
16
#define SOURCE_OPT_CFG_H_
17
18
#include <algorithm>
19
#include <list>
20
#include <unordered_map>
21
#include <unordered_set>
22
#include <vector>
23
24
#include "source/opt/basic_block.h"
25
26
namespace spvtools {
27
namespace opt {
28
29
class CFG {
30
 public:
31
  explicit CFG(Module* module);
32
33
  // Return the list of predecessors for basic block with label |blkid|.
34
  // TODO(dnovillo): Move this to BasicBlock.
35
29.0M
  const std::vector<uint32_t>& preds(uint32_t blk_id) const {
36
29.0M
    assert(label2preds_.count(blk_id));
37
29.0M
    return label2preds_.at(blk_id);
38
29.0M
  }
39
40
  // Return a pointer to the basic block instance corresponding to the label
41
  // |blk_id|.
42
24.9M
  BasicBlock* block(uint32_t blk_id) const { return id2block_.at(blk_id); }
43
44
  // Return the pseudo entry and exit blocks.
45
36.6k
  const BasicBlock* pseudo_entry_block() const { return &pseudo_entry_block_; }
46
84.9k
  BasicBlock* pseudo_entry_block() { return &pseudo_entry_block_; }
47
48
0
  const BasicBlock* pseudo_exit_block() const { return &pseudo_exit_block_; }
49
853k
  BasicBlock* pseudo_exit_block() { return &pseudo_exit_block_; }
50
51
  // Return true if |block_ptr| is the pseudo-entry block.
52
10.9M
  bool IsPseudoEntryBlock(BasicBlock* block_ptr) const {
53
10.9M
    return block_ptr == &pseudo_entry_block_;
54
10.9M
  }
55
56
  // Return true if |block_ptr| is the pseudo-exit block.
57
10.8M
  bool IsPseudoExitBlock(BasicBlock* block_ptr) const {
58
10.8M
    return block_ptr == &pseudo_exit_block_;
59
10.8M
  }
60
61
  // Compute structured block order into |order| for |func| starting at |root|.
62
  // This order has the property that dominators come before all blocks they
63
  // dominate, merge blocks come after all blocks that are in the control
64
  // constructs of their header, and continue blocks come after all of the
65
  // blocks in the body of their loop.
66
  void ComputeStructuredOrder(Function* func, BasicBlock* root,
67
                              std::list<BasicBlock*>* order);
68
69
  // Compute structured block order into |order| for |func| starting at |root|
70
  // and ending at |end|. This order has the property that dominators come
71
  // before all blocks they dominate, merge blocks come after all blocks that
72
  // are in the control constructs of their header, and continue blocks come
73
  // after all the blocks in the body of their loop.
74
  void ComputeStructuredOrder(Function* func, BasicBlock* root, BasicBlock* end,
75
                              std::list<BasicBlock*>* order);
76
77
  // Applies |f| to all blocks that can be reach from |bb| in post order.
78
  void ForEachBlockInPostOrder(BasicBlock* bb,
79
                               const std::function<void(BasicBlock*)>& f);
80
81
  // Applies |f| to all blocks that can be reach from |bb| in reverse post
82
  // order.
83
  void ForEachBlockInReversePostOrder(
84
      BasicBlock* bb, const std::function<void(BasicBlock*)>& f);
85
86
  // Applies |f| to all blocks that can be reach from |bb| in reverse post
87
  // order.  Return false if |f| return false on any basic block, and stops
88
  // processing.
89
  bool WhileEachBlockInReversePostOrder(
90
      BasicBlock* bb, const std::function<bool(BasicBlock*)>& f);
91
92
  // Registers |blk| as a basic block in the cfg, this also updates the
93
  // predecessor lists of each successor of |blk|. |blk| must have a terminator
94
  // instruction at the end of the block.
95
9.29M
  void RegisterBlock(BasicBlock* blk) {
96
9.29M
    assert(blk->begin() != blk->end() &&
97
9.29M
           "Basic blocks must have a terminator before registering.");
98
9.29M
    assert(blk->tail()->IsBlockTerminator() &&
99
9.29M
           "Basic blocks must have a terminator before registering.");
100
9.29M
    uint32_t blk_id = blk->id();
101
9.29M
    id2block_[blk_id] = blk;
102
9.29M
    AddEdges(blk);
103
9.29M
  }
104
105
  // Removes from the CFG any mapping for the basic block id |blk_id|.
106
0
  void ForgetBlock(const BasicBlock* blk) {
107
0
    id2block_.erase(blk->id());
108
0
    label2preds_.erase(blk->id());
109
0
    RemoveSuccessorEdges(blk);
110
0
  }
111
112
2.67k
  void RemoveEdge(uint32_t pred_blk_id, uint32_t succ_blk_id) {
113
2.67k
    auto pred_it = label2preds_.find(succ_blk_id);
114
2.67k
    if (pred_it == label2preds_.end()) return;
115
2.67k
    auto& preds_list = pred_it->second;
116
2.67k
    auto it = std::find(preds_list.begin(), preds_list.end(), pred_blk_id);
117
2.67k
    if (it != preds_list.end()) preds_list.erase(it);
118
2.67k
  }
119
120
  // Registers |blk| to all of its successors.
121
  void AddEdges(BasicBlock* blk);
122
123
  // Registers the basic block id |pred_blk_id| as being a predecessor of the
124
  // basic block id |succ_blk_id|.
125
9.86M
  void AddEdge(uint32_t pred_blk_id, uint32_t succ_blk_id) {
126
9.86M
    label2preds_[succ_blk_id].push_back(pred_blk_id);
127
9.86M
  }
128
129
  // Removes any edges that no longer exist from the predecessor mapping for
130
  // the basic block id |blk_id|.
131
  void RemoveNonExistingEdges(uint32_t blk_id);
132
133
  // Remove all edges that leave |bb|.
134
2.79k
  void RemoveSuccessorEdges(const BasicBlock* bb) {
135
2.79k
    bb->ForEachSuccessorLabel(
136
2.79k
        [bb, this](uint32_t succ_id) { RemoveEdge(bb->id(), succ_id); });
137
2.79k
  }
138
139
  // Divides |block| into two basic blocks.  The first block will have the same
140
  // id as |block| and will become a preheader for the loop.  The other block
141
  // is a new block that will be the new loop header.
142
  //
143
  // Returns a pointer to the new loop header.  Returns |nullptr| if the new
144
  // loop pointer could not be created.
145
  BasicBlock* SplitLoopHeader(BasicBlock* bb);
146
147
 private:
148
  // Compute structured successors for function |func|. A block's structured
149
  // successors are the blocks it branches to together with its declared merge
150
  // block and continue block if it has them. When order matters, the merge
151
  // block and continue block always appear first. This assures correct depth
152
  // first search in the presence of early returns and kills. If the successor
153
  // vector contain duplicates of the merge or continue blocks, they are safely
154
  // ignored by DFS.
155
  void ComputeStructuredSuccessors(Function* func);
156
157
  // Computes the post-order traversal of the cfg starting at |bb| skipping
158
  // nodes in |seen|.  The order of the traversal is appended to |order|, and
159
  // all nodes in the traversal are added to |seen|.
160
  void ComputePostOrderTraversal(BasicBlock* bb,
161
                                 std::vector<BasicBlock*>* order,
162
                                 std::unordered_set<BasicBlock*>* seen);
163
164
  // Module for this CFG.
165
  Module* module_;
166
167
  // Map from block to its structured successor blocks. See
168
  // ComputeStructuredSuccessors() for definition.
169
  std::unordered_map<const BasicBlock*, std::vector<BasicBlock*>>
170
      block2structured_succs_;
171
172
  // Extra block whose successors are all blocks with no predecessors
173
  // in function.
174
  BasicBlock pseudo_entry_block_;
175
176
  // Augmented CFG Exit Block.
177
  BasicBlock pseudo_exit_block_;
178
179
  // Map from block's label id to its predecessor blocks ids
180
  std::unordered_map<uint32_t, std::vector<uint32_t>> label2preds_;
181
182
  // Map from block's label id to block.
183
  std::unordered_map<uint32_t, BasicBlock*> id2block_;
184
};
185
186
}  // namespace opt
187
}  // namespace spvtools
188
189
#endif  // SOURCE_OPT_CFG_H_