• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

daisytuner / sdfglib / 15075964231

16 May 2025 07:28PM UTC coverage: 63.623% (+0.1%) from 63.496%
15075964231

push

github

web-flow
Merge pull request #16 from daisytuner/segfaults

Enable Wall, Werror and Wpedantic

98 of 120 new or added lines in 39 files covered. (81.67%)

4 existing lines in 4 files now uncovered.

8633 of 13569 relevant lines covered (63.62%)

483.97 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

75.36
/src/analysis/users.cpp
1
#include "sdfg/analysis/users.h"
2

3
#include <cassert>
4
#include <list>
5
#include <memory>
6
#include <string>
7
#include <unordered_map>
8
#include <unordered_set>
9
#include <vector>
10

11
#include "sdfg/data_flow/memlet.h"
12
#include "sdfg/element.h"
13
#include "sdfg/graph/graph.h"
14
#include "sdfg/structured_control_flow/for.h"
15
#include "sdfg/structured_control_flow/sequence.h"
16
#include "sdfg/structured_sdfg.h"
17
#include "sdfg/symbolic/symbolic.h"
18

19
namespace sdfg {
20
namespace analysis {
21

22
User::User(graph::Vertex vertex, const std::string& container, Element* element, Use use)
16,227✔
23
    : vertex_(vertex), container_(container), use_(use), element_(element) {
16,227✔
24

25
      };
16,227✔
26

27
User::User(graph::Vertex vertex, const std::string& container, Element* element,
12,297✔
28
           data_flow::DataFlowGraph* parent, Use use)
29
    : vertex_(vertex), container_(container), use_(use), element_(element), parent_(parent) {
12,297✔
30

31
      };
12,297✔
32

33
User::~User() {
51,044✔
34

35
};
51,044✔
36

37
Use User::use() const { return this->use_; };
168,699✔
38

39
std::string& User::container() { return this->container_; };
250,096✔
40

41
Element* User::element() { return this->element_; };
104,625✔
42

43
data_flow::DataFlowGraph* User::parent() { return this->parent_; };
3✔
44

45
const std::vector<data_flow::Subset> User::subsets() const {
2,913✔
46
    if (this->container_ == "") {
2,913✔
47
        return {};
×
48
    }
49

50
    if (auto access_node = dynamic_cast<data_flow::AccessNode*>(this->element_)) {
2,913✔
51
        auto& graph = *this->parent_;
2,902✔
52
        if (this->use_ == Use::READ || this->use_ == Use::VIEW) {
2,902✔
53
            std::vector<data_flow::Subset> subsets;
677✔
54
            for (auto& iedge : graph.out_edges(*access_node)) {
1,379✔
55
                subsets.push_back(iedge.subset());
702✔
56
            }
57
            return subsets;
677✔
58
        } else if (this->use_ == Use::WRITE || this->use_ == Use::MOVE) {
2,902✔
59
            std::vector<data_flow::Subset> subsets;
2,225✔
60
            for (auto& oedge : graph.in_edges(*access_node)) {
4,450✔
61
                subsets.push_back(oedge.subset());
2,225✔
62
            }
63
            return subsets;
2,225✔
64
        }
2,225✔
65
    }
×
66

67
    // Use of symbol
68
    return {{sdfg::symbolic::integer(0)}};
11✔
69
};
2,913✔
70

71
ForUser::ForUser(graph::Vertex vertex, const std::string& container, Element* element, Use use,
6,004✔
72
                 bool is_init, bool is_condition, bool is_update)
73
    : User(vertex, container, element, use),
6,004✔
74
      is_init_(is_init),
6,004✔
75
      is_condition_(is_condition),
6,004✔
76
      is_update_(is_update) {
12,008✔
77

78
      };
6,004✔
79

80
bool ForUser::is_init() const { return this->is_init_; };
6,008✔
81

82
bool ForUser::is_condition() const { return this->is_condition_; };
4,610✔
83

84
bool ForUser::is_update() const { return this->is_update_; };
2,329✔
85

86
void Users::init_dom_tree() {
157✔
87
    this->dom_tree_.clear();
157✔
88
    this->pdom_tree_.clear();
157✔
89

90
    // Compute dominator-tree
91
    auto dom_tree = graph::dominator_tree(this->graph_, this->source_->vertex_);
157✔
92
    for (auto& entry : dom_tree) {
8,799✔
93
        User* first = this->users_.at(entry.first).get();
8,642✔
94
        User* second = nullptr;
8,642✔
95
        if (entry.second != boost::graph_traits<graph::Graph>::null_vertex()) {
8,642✔
96
            second = this->users_.at(entry.second).get();
8,485✔
97
        }
8,485✔
98
        this->dom_tree_.insert({first, second});
8,642✔
99
    }
100

101
    // Compute post-dominator-tree
102
    auto pdom_tree = graph::post_dominator_tree(this->graph_, this->sink_->vertex_);
157✔
103
    for (auto& entry : pdom_tree) {
8,799✔
104
        User* first = this->users_.at(entry.first).get();
8,642✔
105
        User* second = nullptr;
8,642✔
106
        if (entry.second != boost::graph_traits<graph::Graph>::null_vertex()) {
8,642✔
107
            second = this->users_.at(entry.second).get();
8,485✔
108
        }
8,485✔
109
        this->pdom_tree_.insert({first, second});
8,642✔
110
    }
111
};
157✔
112

113
std::pair<graph::Vertex, graph::Vertex> Users::traverse(data_flow::DataFlowGraph& dataflow) {
1,851✔
114
    graph::Vertex first = boost::graph_traits<graph::Graph>::null_vertex();
1,851✔
115
    graph::Vertex last = boost::graph_traits<graph::Graph>::null_vertex();
1,851✔
116
    for (auto node : dataflow.topological_sort()) {
8,813✔
117
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
6,962✔
118
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
4,871✔
119
                if (dataflow.in_degree(*node) > 0) {
4,871✔
120
                    Use use = Use::WRITE;
2,028✔
121
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
4,053✔
122
                        if (iedge.src_conn() == "refs" || iedge.dst_conn() == "refs") {
2,028✔
123
                            use = Use::MOVE;
3✔
124
                            break;
3✔
125
                        }
126
                    }
127

128
                    auto v = boost::add_vertex(this->graph_);
2,028✔
129
                    this->add_user(std::make_unique<User>(v, access_node->data(), access_node,
2,028✔
130
                                                          &dataflow, use));
2,028✔
131

132
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
2,028✔
133
                        boost::add_edge(last, v, this->graph_);
2,003✔
134
                    } else {
2,003✔
135
                        first = v;
25✔
136
                    }
137
                    last = v;
2,028✔
138
                }
2,028✔
139
                if (dataflow.out_degree(*access_node) > 0) {
4,871✔
140
                    Use use = Use::READ;
3,129✔
141
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
6,519✔
142
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
3,393✔
143
                            use = Use::VIEW;
3✔
144
                            break;
3✔
145
                        }
146
                    }
147

148
                    auto v = boost::add_vertex(this->graph_);
3,129✔
149
                    this->add_user(std::make_unique<User>(v, access_node->data(), access_node,
3,129✔
150
                                                          &dataflow, use));
3,129✔
151

152
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
3,129✔
153
                        boost::add_edge(last, v, this->graph_);
1,706✔
154
                    } else {
1,706✔
155
                        first = v;
1,423✔
156
                    }
157
                    last = v;
3,129✔
158
                }
3,129✔
159
            }
4,871✔
160
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
6,962✔
161
            if (tasklet->is_conditional()) {
2,085✔
162
                auto& condition = tasklet->condition();
18✔
163
                for (auto& atom : symbolic::atoms(condition)) {
36✔
164
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
18✔
165
                    auto v = boost::add_vertex(this->graph_);
18✔
166
                    this->add_user(
18✔
167
                        std::make_unique<User>(v, sym->get_name(), tasklet, &dataflow, Use::READ));
18✔
168
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
18✔
169
                        boost::add_edge(last, v, this->graph_);
6✔
170
                    } else {
6✔
171
                        first = v;
12✔
172
                    }
173
                    last = v;
18✔
174
                }
18✔
175
            }
18✔
176
        }
2,085✔
177

178
        for (auto& oedge : dataflow.out_edges(*node)) {
12,380✔
179
            std::unordered_set<std::string> used;
5,418✔
180
            for (auto dim : oedge.subset()) {
13,610✔
181
                for (auto atom : symbolic::atoms(dim)) {
15,387✔
182
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
7,195✔
183
                    if (used.find(sym->get_name()) != used.end()) {
7,195✔
184
                        continue;
73✔
185
                    }
186
                    used.insert(sym->get_name());
7,122✔
187

188
                    auto v = boost::add_vertex(this->graph_);
7,122✔
189
                    this->add_user(
7,122✔
190
                        std::make_unique<User>(v, sym->get_name(), &oedge, &dataflow, Use::READ));
7,122✔
191
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
7,122✔
192
                        boost::add_edge(last, v, this->graph_);
6,808✔
193
                    } else {
6,808✔
194
                        first = v;
314✔
195
                    }
196
                    last = v;
7,122✔
197
                }
7,195✔
198
            }
8,192✔
199
        }
5,418✔
200
    }
201

202
    return {first, last};
1,851✔
203
};
×
204

205
std::pair<graph::Vertex, graph::Vertex> Users::traverse(
5,060✔
206
    structured_control_flow::ControlFlowNode& node) {
207
    if (auto block_stmt = dynamic_cast<structured_control_flow::Block*>(&node)) {
5,060✔
208
        // NOP
209
        auto s = boost::add_vertex(this->graph_);
1,851✔
210
        this->users_.insert({s, std::make_unique<User>(s, "", block_stmt, Use::NOP)});
1,851✔
211
        this->entries_.insert({block_stmt, this->users_.at(s).get()});
1,851✔
212

213
        // NOP
214
        auto t = boost::add_vertex(this->graph_);
1,851✔
215
        this->users_.insert({t, std::make_unique<User>(t, "", block_stmt, Use::NOP)});
1,851✔
216
        this->exits_.insert({block_stmt, this->users_.at(t).get()});
1,851✔
217

218
        auto& dataflow = block_stmt->dataflow();
1,851✔
219
        auto subgraph = this->traverse(dataflow);
1,851✔
220

221
        // May be empty
222
        if (subgraph.first == boost::graph_traits<graph::Graph>::null_vertex()) {
1,851✔
223
            boost::add_edge(s, t, this->graph_);
77✔
224
            return {s, t};
77✔
225
        }
226

227
        boost::add_edge(s, subgraph.first, this->graph_);
1,774✔
228
        boost::add_edge(subgraph.second, t, this->graph_);
1,774✔
229

230
        return {s, t};
1,774✔
231
    } else if (auto sequence_stmt = dynamic_cast<structured_control_flow::Sequence*>(&node)) {
3,209✔
232
        auto s = boost::add_vertex(this->graph_);
1,994✔
233
        this->users_.insert({s, std::make_unique<User>(s, "", sequence_stmt, Use::NOP)});
1,994✔
234
        this->entries_.insert({sequence_stmt, this->users_.at(s).get()});
1,994✔
235

236
        graph::Vertex current = s;
1,994✔
237
        for (size_t i = 0; i < sequence_stmt->size(); i++) {
4,954✔
238
            auto child = sequence_stmt->at(i);
2,960✔
239

240
            auto subgraph = this->traverse(child.first);
2,960✔
241
            boost::add_edge(current, subgraph.first, this->graph_);
2,960✔
242
            current = subgraph.second;
2,960✔
243

244
            std::unordered_set<std::string> used;
2,960✔
245
            for (auto& entry : child.second.assignments()) {
3,024✔
246
                for (auto atom : symbolic::atoms(entry.second)) {
91✔
247
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
27✔
248
                    if (symbolic::is_pointer(sym)) {
27✔
249
                        continue;
×
250
                    }
251
                    if (used.find(sym->get_name()) != used.end()) {
27✔
252
                        continue;
×
253
                    }
254
                    used.insert(sym->get_name());
27✔
255

256
                    auto v = boost::add_vertex(this->graph_);
27✔
257
                    this->add_user(
27✔
258
                        std::make_unique<User>(v, sym->get_name(), &child.second, Use::READ));
27✔
259

260
                    boost::add_edge(current, v, this->graph_);
27✔
261
                    current = v;
27✔
262
                }
27✔
263
            }
264

265
            for (auto& entry : child.second.assignments()) {
3,024✔
266
                auto v = boost::add_vertex(this->graph_);
64✔
267
                this->add_user(
64✔
268
                    std::make_unique<User>(v, entry.first->get_name(), &child.second, Use::WRITE));
64✔
269

270
                boost::add_edge(current, v, this->graph_);
64✔
271
                current = v;
64✔
272
            }
273
        }
2,960✔
274

275
        if (current == boost::graph_traits<graph::Graph>::null_vertex()) {
1,994✔
276
            this->exits_.insert({sequence_stmt, this->users_.at(s).get()});
×
277
            return {s, current};
×
278
        }
279

280
        auto t = boost::add_vertex(this->graph_);
1,994✔
281
        this->users_.insert({t, std::make_unique<User>(t, "", sequence_stmt, Use::NOP)});
1,994✔
282
        boost::add_edge(current, t, this->graph_);
1,994✔
283
        this->exits_.insert({sequence_stmt, this->users_.at(t).get()});
1,994✔
284

285
        return {s, t};
1,994✔
286
    } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(&node)) {
1,215✔
287
        // NOP
288
        auto s = boost::add_vertex(this->graph_);
24✔
289
        this->users_.insert({s, std::make_unique<User>(s, "", if_else_stmt, Use::NOP)});
24✔
290
        this->entries_.insert({if_else_stmt, this->users_.at(s).get()});
24✔
291

292
        graph::Vertex last = s;
24✔
293

294
        std::unordered_set<std::string> used;
24✔
295
        for (size_t i = 0; i < if_else_stmt->size(); i++) {
67✔
296
            auto& condition = if_else_stmt->at(i).second;
43✔
297
            for (auto atom : symbolic::atoms(condition)) {
82✔
298
                auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
39✔
299
                if (used.find(sym->get_name()) != used.end()) {
39✔
300
                    continue;
17✔
301
                }
302
                used.insert(sym->get_name());
22✔
303

304
                auto v = boost::add_vertex(this->graph_);
22✔
305

306
                this->add_user(std::make_unique<User>(v, sym->get_name(), if_else_stmt, Use::READ));
22✔
307

308
                boost::add_edge(last, v, this->graph_);
22✔
309
                last = v;
22✔
310
            }
39✔
311
        }
43✔
312

313
        // NOP
314
        auto t = boost::add_vertex(this->graph_);
24✔
315
        this->users_.insert({t, std::make_unique<User>(t, "", if_else_stmt, Use::NOP)});
24✔
316
        this->exits_.insert({if_else_stmt, this->users_.at(t).get()});
24✔
317

318
        // Forward edge: Potentially missing else case
319
        if (!if_else_stmt->is_complete()) {
24✔
320
            boost::add_edge(last, t, this->graph_);
6✔
321
        }
6✔
322

323
        for (size_t i = 0; i < if_else_stmt->size(); i++) {
67✔
324
            auto branch = if_else_stmt->at(i);
43✔
325
            auto subgraph = this->traverse(branch.first);
43✔
326
            boost::add_edge(last, subgraph.first, this->graph_);
43✔
327
            if (subgraph.second != boost::graph_traits<graph::Graph>::null_vertex()) {
43✔
328
                boost::add_edge(subgraph.second, t, this->graph_);
43✔
329
            }
43✔
330
        }
43✔
331

332
        return {s, t};
24✔
333
    } else if (auto loop_stmt = dynamic_cast<structured_control_flow::While*>(&node)) {
1,215✔
334
        // NOP
335
        auto s = boost::add_vertex(this->graph_);
10✔
336
        this->users_.insert({s, std::make_unique<User>(s, "", loop_stmt, Use::NOP)});
10✔
337
        this->entries_.insert({loop_stmt, this->users_.at(s).get()});
10✔
338

339
        auto subgraph = this->traverse(loop_stmt->root());
10✔
340

341
        // NOP
342
        auto t = boost::add_vertex(this->graph_);
10✔
343
        this->users_.insert({t, std::make_unique<User>(t, "", loop_stmt, Use::NOP)});
10✔
344
        this->exits_.insert({loop_stmt, this->users_.at(t).get()});
10✔
345

346
        boost::add_edge(s, subgraph.first, this->graph_);
10✔
347
        if (subgraph.second != boost::graph_traits<graph::Graph>::null_vertex()) {
10✔
348
            boost::add_edge(subgraph.second, t, this->graph_);
10✔
349
        }
10✔
350

351
        // Empty loop
352
        boost::add_edge(s, t, this->graph_);
10✔
353
        // Back edge
354
        boost::add_edge(t, s, this->graph_);
10✔
355

356
        return {s, t};
10✔
357
    } else if (auto for_stmt = dynamic_cast<structured_control_flow::For*>(&node)) {
1,181✔
358
        // NOP
359
        auto s = boost::add_vertex(this->graph_);
1,162✔
360
        this->users_.insert({s, std::make_unique<User>(s, "", for_stmt, Use::NOP)});
1,162✔
361
        auto last = s;
1,162✔
362
        this->entries_.insert({for_stmt, this->users_.at(s).get()});
1,162✔
363

364
        // NOP
365
        auto t = boost::add_vertex(this->graph_);
1,162✔
366
        this->users_.insert({t, std::make_unique<User>(t, "", for_stmt, Use::NOP)});
1,162✔
367
        this->exits_.insert({for_stmt, this->users_.at(t).get()});
1,162✔
368

369
        // Init
370
        for (auto atom : symbolic::atoms(for_stmt->init())) {
1,397✔
371
            auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
235✔
372
            auto v = boost::add_vertex(this->graph_);
235✔
373
            this->add_user(std::make_unique<ForUser>(v, sym->get_name(), for_stmt, Use::READ, true,
235✔
374
                                                     false, false));
235✔
375
            boost::add_edge(last, v, this->graph_);
235✔
376
            last = v;
235✔
377
        }
235✔
378
        // Indvar
379
        auto v = boost::add_vertex(this->graph_);
1,162✔
380
        this->add_user(std::make_unique<ForUser>(v, for_stmt->indvar()->get_name(), for_stmt,
2,324✔
381
                                                 Use::WRITE, true, false, false));
1,162✔
382

383
        boost::add_edge(last, v, this->graph_);
1,162✔
384
        last = v;
1,162✔
385

386
        // Condition
387
        for (auto atom : symbolic::atoms(for_stmt->condition())) {
3,445✔
388
            auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
2,283✔
389
            auto v = boost::add_vertex(this->graph_);
2,283✔
390
            this->add_user(std::make_unique<ForUser>(v, sym->get_name(), for_stmt, Use::READ, false,
2,283✔
391
                                                     true, false));
2,283✔
392

393
            boost::add_edge(last, v, this->graph_);
2,283✔
394
            boost::add_edge(v, t, this->graph_);
2,283✔
395
            last = v;
2,283✔
396
        }
2,283✔
397

398
        auto subgraph = this->traverse(for_stmt->root());
1,162✔
399
        boost::add_edge(last, subgraph.first, this->graph_);
1,162✔
400

401
        // Update
402
        auto end = subgraph.second;
1,162✔
403
        for (auto atom : symbolic::atoms(for_stmt->update())) {
2,324✔
404
            auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
1,162✔
405
            auto v = boost::add_vertex(this->graph_);
1,162✔
406
            this->add_user(std::make_unique<ForUser>(v, sym->get_name(), for_stmt, Use::READ, false,
1,162✔
407
                                                     false, true));
1,162✔
408
            boost::add_edge(end, v, this->graph_);
1,162✔
409
            end = v;
1,162✔
410
        }
1,162✔
411

412
        auto update_v = boost::add_vertex(this->graph_);
1,162✔
413
        this->add_user(std::make_unique<ForUser>(update_v, for_stmt->indvar()->get_name(), for_stmt,
2,324✔
414
                                                 Use::WRITE, false, false, true));
1,162✔
415

416
        if (end != boost::graph_traits<graph::Graph>::null_vertex()) {
1,162✔
417
            boost::add_edge(end, update_v, this->graph_);
1,162✔
418
        }
1,162✔
419
        end = update_v;
1,162✔
420

421
        if (end != boost::graph_traits<graph::Graph>::null_vertex()) {
1,162✔
422
            boost::add_edge(end, t, this->graph_);
1,162✔
423
        }
1,162✔
424

425
        // Back edge
426
        boost::add_edge(t, last, this->graph_);
1,162✔
427

428
        return {s, t};
1,162✔
429
    } else if (auto cont_stmt = dynamic_cast<structured_control_flow::Continue*>(&node)) {
19✔
430
        // Approximated by general back edge in loop scope
431
        auto v = boost::add_vertex(this->graph_);
5✔
432
        this->users_.insert({v, std::make_unique<User>(v, "", cont_stmt, Use::NOP)});
5✔
433
        this->entries_.insert({cont_stmt, this->users_.at(v).get()});
5✔
434
        this->exits_.insert({cont_stmt, this->users_.at(v).get()});
5✔
435
        return {v, v};
5✔
436
    } else if (auto br_stmt = dynamic_cast<structured_control_flow::Break*>(&node)) {
14✔
437
        // Approximated by general back edge in loop scope
438
        auto v = boost::add_vertex(this->graph_);
5✔
439
        this->users_.insert({v, std::make_unique<User>(v, "", br_stmt, Use::NOP)});
5✔
440
        this->entries_.insert({br_stmt, this->users_.at(v).get()});
5✔
441
        this->exits_.insert({br_stmt, this->users_.at(v).get()});
5✔
442
        return {v, v};
5✔
443
    } else if (auto ret_stmt = dynamic_cast<structured_control_flow::Return*>(&node)) {
9✔
444
        auto v = boost::add_vertex(this->graph_);
×
NEW
445
        this->users_.insert({v, std::make_unique<User>(v, "", ret_stmt, Use::NOP)});
×
NEW
446
        this->entries_.insert({ret_stmt, this->users_.at(v).get()});
×
NEW
447
        this->exits_.insert({ret_stmt, this->users_.at(v).get()});
×
UNCOV
448
        return {v, boost::graph_traits<graph::Graph>::null_vertex()};
×
449
    } else if (auto kern_stmt = dynamic_cast<structured_control_flow::Kernel*>(&node)) {
9✔
450
        // NOP
451
        auto s = boost::add_vertex(this->graph_);
9✔
452
        this->users_.insert({s, std::make_unique<User>(s, "", kern_stmt, Use::NOP)});
9✔
453
        this->entries_.insert({kern_stmt, this->users_.at(s).get()});
9✔
454

455
        auto subgraph = this->traverse(kern_stmt->root());
9✔
456
        boost::add_edge(s, subgraph.first, this->graph_);
9✔
457
        if (subgraph.second == boost::graph_traits<graph::Graph>::null_vertex()) {
9✔
458
            this->exits_.insert({kern_stmt, this->users_.at(s).get()});
×
459
            return {s, subgraph.second};
×
460
        }
461

462
        auto t = boost::add_vertex(this->graph_);
9✔
463
        this->users_.insert({t, std::make_unique<User>(t, "", kern_stmt, Use::NOP)});
9✔
464
        boost::add_edge(subgraph.second, t, this->graph_);
9✔
465
        this->exits_.insert({kern_stmt, this->users_.at(t).get()});
9✔
466

467
        return {s, t};
9✔
468
    }
469

470
    assert(false);
×
471
};
5,060✔
472

473
Users::Users(StructuredSDFG& sdfg)
212✔
474
    : Analysis(sdfg), node_(sdfg.root()) {
212✔
475

476
      };
212✔
477

478
Users::Users(StructuredSDFG& sdfg, structured_control_flow::ControlFlowNode& node)
1,328✔
479
    : Analysis(sdfg), node_(node) {
664✔
480

481
      };
664✔
482

483
void Users::run(analysis::AnalysisManager& analysis_manager) {
876✔
484
    users_.clear();
876✔
485
    graph_.clear();
876✔
486
    source_ = nullptr;
876✔
487
    sink_ = nullptr;
876✔
488
    dom_tree_.clear();
876✔
489
    pdom_tree_.clear();
876✔
490
    users_by_sdfg_.clear();
876✔
491
    users_by_sdfg_loop_condition_.clear();
876✔
492
    users_by_sdfg_loop_init_.clear();
876✔
493
    users_by_sdfg_loop_update_.clear();
876✔
494

495
    reads_.clear();
876✔
496
    writes_.clear();
876✔
497
    views_.clear();
876✔
498
    moves_.clear();
876✔
499

500
    this->traverse(node_);
876✔
501
    if (this->users_.empty()) {
876✔
502
        return;
×
503
    }
504

505
    // Require a single source
506
    for (auto& entry : this->users_) {
29,400✔
507
        if (boost::in_degree(entry.first, this->graph_) == 0) {
28,524✔
508
            assert(this->source_ == nullptr);
876✔
509
            this->source_ = entry.second.get();
876✔
510
        }
876✔
511
    }
512
    assert(this->source_ != nullptr);
876✔
513

514
    // Sink may be empty
515
    for (auto& entry : this->users_) {
29,400✔
516
        if (boost::out_degree(entry.first, this->graph_) == 0) {
28,524✔
517
            assert(this->sink_ == nullptr);
806✔
518
            this->sink_ = entry.second.get();
806✔
519
        }
806✔
520
    }
521

522
    // Collect sub structures
523
    for (auto& entry : this->users_) {
29,400✔
524
        auto container = entry.second->container();
28,524✔
525
        switch (entry.second->use()) {
28,524✔
526
            case Use::READ: {
527
                if (this->reads_.find(container) == this->reads_.end()) {
13,995✔
528
                    this->reads_.insert({container, {}});
5,264✔
529
                }
5,264✔
530
                this->reads_[container].push_back(entry.second.get());
13,995✔
531
                break;
13,995✔
532
            }
533
            case Use::WRITE: {
534
                if (this->writes_.find(container) == this->writes_.end()) {
4,413✔
535
                    this->writes_.insert({container, {}});
2,743✔
536
                }
2,743✔
537
                this->writes_[container].push_back(entry.second.get());
4,413✔
538
                break;
4,413✔
539
            }
540
            case Use::VIEW: {
541
                if (this->views_.find(container) == this->views_.end()) {
3✔
542
                    this->views_.insert({container, {}});
3✔
543
                }
3✔
544
                this->views_[container].push_back(entry.second.get());
3✔
545
                break;
3✔
546
            }
547
            case Use::MOVE: {
548
                if (this->moves_.find(container) == this->moves_.end()) {
3✔
549
                    this->moves_.insert({container, {}});
3✔
550
                }
3✔
551
                this->moves_[container].push_back(entry.second.get());
3✔
552
                break;
3✔
553
            }
554
            default:
555
                break;
10,110✔
556
        }
557
    }
28,524✔
558
};
876✔
559

560
std::vector<User*> Users::uses() const {
×
561
    std::vector<User*> us;
×
562
    for (auto& entry : this->users_) {
×
563
        if (entry.second->use() == Use::NOP) {
×
564
            continue;
×
565
        }
566
        us.push_back(entry.second.get());
×
567
    }
568

569
    return us;
×
570
};
×
571

572
std::vector<User*> Users::uses(const std::string& container) const {
1✔
573
    std::vector<User*> us;
1✔
574
    for (auto& entry : this->users_) {
10✔
575
        if (entry.second->container() != container) {
9✔
576
            continue;
7✔
577
        }
578
        if (entry.second->use() == Use::NOP) {
2✔
579
            continue;
×
580
        }
581
        us.push_back(entry.second.get());
2✔
582
    }
583

584
    return us;
1✔
585
};
1✔
586

587
std::vector<User*> Users::writes() const {
×
588
    std::vector<User*> us;
×
589
    for (auto& entry : this->users_) {
×
590
        if (entry.second->use() != Use::WRITE) {
×
591
            continue;
×
592
        }
593
        us.push_back(entry.second.get());
×
594
    }
595

596
    return us;
×
597
};
×
598

599
std::vector<User*> Users::writes(const std::string& container) const {
66✔
600
    if (this->writes_.find(container) == this->writes_.end()) {
66✔
601
        return {};
25✔
602
    } else {
603
        return this->writes_.at(container);
41✔
604
    }
605
};
66✔
606

607
std::vector<User*> Users::reads() const {
×
608
    std::vector<User*> us;
×
609
    for (auto& entry : this->users_) {
×
610
        if (entry.second->use() != Use::READ) {
×
611
            continue;
×
612
        }
613
        us.push_back(entry.second.get());
×
614
    }
615

616
    return us;
×
617
};
×
618

619
std::vector<User*> Users::reads(const std::string& container) const {
33✔
620
    if (this->reads_.find(container) == this->reads_.end()) {
33✔
621
        return {};
13✔
622
    } else {
623
        return this->reads_.at(container);
20✔
624
    }
625
};
33✔
626

627
std::vector<User*> Users::views() const {
×
628
    std::vector<User*> us;
×
629
    for (auto& entry : this->users_) {
×
630
        if (entry.second->use() != Use::VIEW) {
×
631
            continue;
×
632
        }
633
        us.push_back(entry.second.get());
×
634
    }
635

636
    return us;
×
637
};
×
638

639
std::vector<User*> Users::views(const std::string& container) const {
71✔
640
    if (this->views_.find(container) == this->views_.end()) {
71✔
641
        return {};
71✔
642
    } else {
643
        return this->views_.at(container);
×
644
    }
645
};
71✔
646

647
std::vector<User*> Users::moves() const {
×
648
    std::vector<User*> us;
×
649
    for (auto& entry : this->users_) {
×
650
        if (entry.second->use() != Use::MOVE) {
×
651
            continue;
×
652
        }
653
        us.push_back(entry.second.get());
×
654
    }
655

656
    return us;
×
657
};
×
658

659
std::vector<User*> Users::moves(const std::string& container) const {
77✔
660
    if (this->moves_.find(container) == this->moves_.end()) {
77✔
661
        return {};
76✔
662
    } else {
663
        return this->moves_.at(container);
1✔
664
    }
665
};
77✔
666

667
/****** Domination Analysis ******/
668

669
const std::unordered_map<User*, User*>& Users::dominator_tree() {
×
670
    if (this->dom_tree_.empty()) {
×
671
        this->init_dom_tree();
×
672
    }
×
673
    return this->dom_tree_;
×
674
};
675

676
bool Users::dominates(User& user1, User& user) {
1,526✔
677
    if (this->dom_tree_.empty()) {
1,526✔
678
        this->init_dom_tree();
157✔
679
    }
157✔
680
    auto dominator = this->dom_tree_.at(&user);
1,526✔
681
    while (dominator != nullptr) {
14,585✔
682
        if (dominator == &user1) {
14,585✔
683
            return true;
1,526✔
684
        }
685
        dominator = this->dom_tree_.at(dominator);
13,059✔
686
    }
687
    return false;
×
688
};
1,526✔
689

690
const std::unordered_map<User*, User*>& Users::post_dominator_tree() {
×
691
    if (this->pdom_tree_.empty()) {
×
692
        this->init_dom_tree();
×
693
    }
×
694
    return this->pdom_tree_;
×
695
};
696

697
bool Users::post_dominates(User& user1, User& user) {
749✔
698
    if (this->pdom_tree_.empty()) {
749✔
699
        this->init_dom_tree();
×
700
    }
×
701
    auto dominator = this->pdom_tree_.at(&user);
749✔
702
    while (dominator != nullptr) {
7,232✔
703
        if (dominator == &user1) {
7,232✔
704
            return true;
749✔
705
        }
706
        dominator = this->pdom_tree_.at(dominator);
6,483✔
707
    }
708
    return false;
×
709
};
749✔
710

711
const std::unordered_set<User*> Users::all_uses_between(User& user1, User& user) {
757✔
712
    assert(this->dominates(user1, user));
757✔
713

714
    std::unordered_set<User*> uses;
757✔
715
    std::unordered_set<User*> visited;
757✔
716
    std::list<User*> queue = {&user};
757✔
717
    while (!queue.empty()) {
25,403✔
718
        auto current = queue.front();
24,646✔
719
        queue.pop_front();
24,646✔
720

721
        // Stop conditions
722
        if (current == &user1) {
24,646✔
723
            continue;
757✔
724
        }
725

726
        if (visited.find(current) != visited.end()) {
23,889✔
727
            continue;
2,374✔
728
        }
729
        visited.insert(current);
21,515✔
730

731
        if (current != &user1 && current != &user) {
21,515✔
732
            uses.insert(current);
20,758✔
733
        }
20,758✔
734

735
        // Extend search
736
        // Backward search to utilize domination user1 over user
737
        auto [eb, ee] = boost::in_edges(current->vertex_, this->graph_);
21,515✔
738
        auto edges = std::ranges::subrange(eb, ee);
43,030✔
739
        for (auto edge : edges) {
45,404✔
740
            auto v = boost::source(edge, this->graph_);
23,889✔
741
            queue.push_back(this->users_.at(v).get());
23,889✔
742
        }
743
    }
744

745
    return uses;
757✔
746
};
757✔
747

748
const std::unordered_set<User*> Users::all_uses_after(User& user1) {
×
749
    std::unordered_set<User*> uses;
×
750
    std::unordered_set<User*> visited;
×
751
    std::list<User*> queue = {&user1};
×
752
    while (!queue.empty()) {
×
753
        auto current = queue.front();
×
754
        queue.pop_front();
×
755
        if (visited.find(current) != visited.end()) {
×
756
            continue;
×
757
        }
758
        visited.insert(current);
×
759

760
        if (current != &user1) {
×
761
            uses.insert(current);
×
762
        }
×
763

764
        // Extend search
765
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
766
        auto edges = std::ranges::subrange(eb, ee);
×
767
        for (auto edge : edges) {
×
768
            auto v = boost::target(edge, this->graph_);
×
769
            queue.push_back(this->users_.at(v).get());
×
770
        }
771
    }
772

773
    return uses;
×
774
};
×
775

776
const std::unordered_set<User*> Users::sources(const std::string& container) const {
2✔
777
    auto source = this->source_;
2✔
778

779
    std::unordered_set<User*> sources;
2✔
780
    std::unordered_set<User*> visited;
2✔
781
    std::list<User*> queue = {source};
2✔
782
    while (!queue.empty()) {
9✔
783
        auto current = queue.front();
7✔
784
        queue.pop_front();
7✔
785
        if (visited.find(current) != visited.end()) {
7✔
786
            continue;
×
787
        }
788
        visited.insert(current);
7✔
789

790
        if (current->container() == container) {
7✔
791
            sources.insert(current);
2✔
792
            continue;
2✔
793
        }
794

795
        // Extend search
796
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
5✔
797
        auto edges = std::ranges::subrange(eb, ee);
10✔
798
        for (auto edge : edges) {
10✔
799
            auto v = boost::target(edge, this->graph_);
5✔
800
            queue.push_back(this->users_.at(v).get());
5✔
801
        }
802
    }
803

804
    return sources;
2✔
805
};
2✔
806

807
/****** Happens-Before Analysis ******/
808

809
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::read_subsets() {
×
810
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
×
811
    for (auto& read : this->users_) {
×
812
        if (read.second->use() != Use::READ) {
×
813
            continue;
×
814
        }
815

816
        auto& data = read.second->container();
×
817
        if (readset.find(data) == readset.end()) {
×
818
            readset[data] = std::vector<data_flow::Subset>();
×
819
        }
×
820
        auto& subsets = read.second->subsets();
×
821
        for (auto& subset : subsets) {
×
822
            readset[data].push_back(subset);
×
823
        }
824
    }
×
825
    return readset;
×
826
};
×
827

828
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::write_subsets() {
×
829
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
830
    for (auto& write : this->users_) {
×
831
        if (write.second->use() != Use::WRITE) {
×
832
            continue;
×
833
        }
834

835
        auto& data = write.second->container();
×
836
        if (writeset.find(data) == writeset.end()) {
×
837
            writeset[data] = std::vector<data_flow::Subset>();
×
838
        }
×
839
        auto& subsets = write.second->subsets();
×
840
        for (auto& subset : subsets) {
×
841
            writeset[data].push_back(subset);
×
842
        }
843
    }
×
844
    return writeset;
×
845
};
×
846

847
std::unordered_set<std::string> Users::locals(StructuredSDFG& sdfg,
558✔
848
                                              structured_control_flow::ControlFlowNode& node) {
849
    // Collect all node elements
850
    Users local_users(sdfg, node);
558✔
851
    analysis::AnalysisManager analysis_manager(sdfg_);
558✔
852
    local_users.run(analysis_manager);
558✔
853
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
558✔
854
    for (auto& entry : local_users.users_) {
17,892✔
855
        if (entry.second->use() == Use::NOP) {
17,334✔
856
            continue;
5,778✔
857
        }
858
        if (!sdfg.is_transient(entry.second->container())) {
11,556✔
859
            continue;
3,152✔
860
        }
861

862
        if (elements.find(entry.second->container()) == elements.end()) {
8,404✔
863
            elements[entry.second->container()] = {};
1,966✔
864
        }
1,966✔
865
        elements[entry.second->container()].insert(entry.second->element());
8,404✔
866
    }
867

868
    // Determine locals
869
    for (auto& entry : this->users_) {
43,465✔
870
        if (entry.second->use() == Use::NOP) {
42,907✔
871
            continue;
15,732✔
872
        }
873

874
        auto& container = entry.second->container();
27,175✔
875
        auto element = entry.second->element();
27,175✔
876
        if (elements.find(container) == elements.end()) {
27,175✔
877
            continue;
20,643✔
878
        }
879
        // used outside of node
880
        if (elements[container].find(element) == elements[container].end()) {
6,532✔
881
            elements.erase(container);
978✔
882
        }
978✔
883
    }
884

885
    std::unordered_set<std::string> locals;
558✔
886
    for (auto& entry : elements) {
1,546✔
887
        locals.insert(entry.first);
988✔
888
    }
889
    return locals;
558✔
890
};
558✔
891

892
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
743✔
893
    auto& entry = users.entries_.at(&node);
743✔
894
    auto& exit = users.exits_.at(&node);
743✔
895
    assert(users.dominates(*entry, *exit));
743✔
896
    assert(users.post_dominates(*exit, *entry));
743✔
897

898
    this->entry_ = entry;
743✔
899
    this->exit_ = exit;
743✔
900
    this->sub_users_ = users.all_uses_between(*entry, *exit);
743✔
901
};
743✔
902

903
std::vector<User*> UsersView::uses() const {
106✔
904
    std::vector<User*> us;
106✔
905
    for (auto& user : this->sub_users_) {
1,790✔
906
        if (user->use() == Use::NOP) {
1,684✔
907
            continue;
392✔
908
        }
909
        us.push_back(user);
1,292✔
910
    }
911

912
    return us;
106✔
913
};
106✔
914

915
std::vector<User*> UsersView::uses(const std::string& container) const {
20✔
916
    std::vector<User*> us;
20✔
917
    for (auto& user : this->sub_users_) {
715✔
918
        if (user->container() != container) {
695✔
919
            continue;
646✔
920
        }
921
        if (user->use() == Use::NOP) {
49✔
922
            continue;
×
923
        }
924
        us.push_back(user);
49✔
925
    }
926

927
    return us;
20✔
928
};
20✔
929

930
std::vector<User*> UsersView::writes() const {
516✔
931
    std::vector<User*> us;
516✔
932
    for (auto& user : this->sub_users_) {
14,232✔
933
        if (user->use() != Use::WRITE) {
13,716✔
934
            continue;
11,597✔
935
        }
936
        us.push_back(user);
2,119✔
937
    }
938

939
    return us;
516✔
940
};
516✔
941

942
std::vector<User*> UsersView::writes(const std::string& container) const {
669✔
943
    std::vector<User*> us;
669✔
944
    for (auto& user : this->sub_users_) {
21,661✔
945
        if (user->container() != container) {
20,992✔
946
            continue;
19,402✔
947
        }
948
        if (user->use() != Use::WRITE) {
1,590✔
949
            continue;
764✔
950
        }
951
        us.push_back(user);
826✔
952
    }
953

954
    return us;
669✔
955
};
669✔
956

957
std::vector<User*> UsersView::reads() const {
509✔
958
    std::vector<User*> us;
509✔
959
    for (auto& user : this->sub_users_) {
14,164✔
960
        if (user->use() != Use::READ) {
13,655✔
961
            continue;
6,066✔
962
        }
963
        us.push_back(user);
7,589✔
964
    }
965

966
    return us;
509✔
967
};
509✔
968

969
std::vector<User*> UsersView::reads(const std::string& container) const {
537✔
970
    std::vector<User*> us;
537✔
971
    for (auto& user : this->sub_users_) {
17,676✔
972
        if (user->container() != container) {
17,139✔
973
            continue;
15,866✔
974
        }
975
        if (user->use() != Use::READ) {
1,273✔
976
            continue;
665✔
977
        }
978
        us.push_back(user);
608✔
979
    }
980

981
    return us;
537✔
982
};
537✔
983

984
std::vector<User*> UsersView::views() const {
459✔
985
    std::vector<User*> us;
459✔
986
    for (auto& user : this->sub_users_) {
11,583✔
987
        if (user->use() != Use::VIEW) {
11,124✔
988
            continue;
11,124✔
989
        }
990
        us.push_back(user);
×
991
    }
992

993
    return us;
459✔
994
};
459✔
995

996
std::vector<User*> UsersView::views(const std::string& container) const {
1✔
997
    std::vector<User*> us;
1✔
998
    for (auto& user : this->sub_users_) {
28✔
999
        if (user->container() != container) {
27✔
1000
            continue;
26✔
1001
        }
1002
        if (user->use() != Use::VIEW) {
1✔
1003
            continue;
1✔
1004
        }
1005
        us.push_back(user);
×
1006
    }
1007

1008
    return us;
1✔
1009
};
1✔
1010

1011
std::vector<User*> UsersView::moves() const {
459✔
1012
    std::vector<User*> us;
459✔
1013
    for (auto& user : this->sub_users_) {
11,583✔
1014
        if (user->use() != Use::MOVE) {
11,124✔
1015
            continue;
11,124✔
1016
        }
1017
        us.push_back(user);
×
1018
    }
1019

1020
    return us;
459✔
1021
};
459✔
1022

1023
std::vector<User*> UsersView::moves(const std::string& container) const {
5✔
1024
    std::vector<User*> us;
5✔
1025
    for (auto& user : this->sub_users_) {
140✔
1026
        if (user->container() != container) {
135✔
1027
            continue;
122✔
1028
        }
1029
        if (user->use() != Use::MOVE) {
13✔
1030
            continue;
13✔
1031
        }
1032
        us.push_back(user);
×
1033
    }
1034

1035
    return us;
5✔
1036
};
5✔
1037

1038
std::unordered_map<User*, User*> UsersView::dominator_tree() {
×
1039
    if (!this->sub_dom_tree_.empty()) {
×
1040
        return this->sub_dom_tree_;
×
1041
    }
1042

1043
    auto dom_tree = this->users_.dominator_tree();
×
1044
    std::unordered_map<User*, User*> sub_dom_tree;
×
1045
    for (auto& entry : this->sub_users_) {
×
1046
        sub_dom_tree[entry] = dom_tree[entry];
×
1047
    }
1048
    sub_dom_tree[this->entry_] = nullptr;
×
1049
    return sub_dom_tree;
×
1050
};
×
1051

1052
bool UsersView::dominates(User& user1, User& user) {
×
1053
    auto dom_tree = this->dominator_tree();
×
1054
    auto dominator = dom_tree[&user];
×
1055
    while (dominator != nullptr) {
×
1056
        if (dominator == &user1) {
×
1057
            return true;
×
1058
        }
1059
        dominator = dom_tree[dominator];
×
1060
    }
1061
    return false;
×
1062
};
×
1063

1064
std::unordered_map<User*, User*> UsersView::post_dominator_tree() {
×
1065
    if (!this->sub_pdom_tree_.empty()) {
×
1066
        return this->sub_pdom_tree_;
×
1067
    }
1068

1069
    auto pdom_tree = this->users_.post_dominator_tree();
×
1070
    std::unordered_map<User*, User*> sub_pdom_tree;
×
1071
    for (auto& entry : this->sub_users_) {
×
1072
        sub_pdom_tree[entry] = pdom_tree[entry];
×
1073
    }
1074
    sub_pdom_tree[this->exit_] = nullptr;
×
1075
    return sub_pdom_tree;
×
1076
};
×
1077

1078
bool UsersView::post_dominates(User& user1, User& user) {
×
1079
    auto pdom_tree = this->post_dominator_tree();
×
1080
    auto dominator = pdom_tree[&user];
×
1081
    while (dominator != nullptr) {
×
1082
        if (dominator == &user1) {
×
1083
            return true;
×
1084
        }
1085
        dominator = pdom_tree[dominator];
×
1086
    }
1087
    return false;
×
1088
};
×
1089

1090
std::unordered_set<User*> UsersView::all_uses_between(User& user1, User& user) {
×
1091
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1092
    assert(this->sub_users_.find(&user) != this->sub_users_.end());
×
1093
    assert(this->dominates(user1, user));
×
1094
    bool post_dominates = this->post_dominates(user, user1);
×
1095

1096
    std::unordered_set<User*> uses;
×
1097
    std::unordered_set<User*> visited;
×
1098
    std::list<User*> queue = {&user1};
×
1099
    while (!queue.empty()) {
×
1100
        auto current = queue.front();
×
1101
        queue.pop_front();
×
1102
        if (visited.find(current) != visited.end()) {
×
1103
            continue;
×
1104
        }
1105
        visited.insert(current);
×
1106

1107
        if (current != &user1 && current != &user) {
×
1108
            uses.insert(current);
×
1109
        }
×
1110

1111
        // Stop conditions
1112
        if (current == exit_) {
×
1113
            continue;
×
1114
        }
1115

1116
        if (current == &user) {
×
1117
            continue;
×
1118
        } else if (!post_dominates) {
×
1119
            if (this->post_dominates(*current, user)) {
×
1120
                continue;
×
1121
            }
1122
        }
×
1123

1124
        // Extend search
1125
        auto [eb, ee] = boost::out_edges(current->vertex_, this->users_.graph_);
×
1126
        auto edges = std::ranges::subrange(eb, ee);
×
1127
        for (auto edge : edges) {
×
1128
            auto v = boost::target(edge, this->users_.graph_);
×
1129
            queue.push_back(this->users_.users_.at(v).get());
×
1130
        }
1131
    }
1132

1133
    return uses;
×
1134
};
×
1135

1136
std::unordered_set<User*> UsersView::all_uses_after(User& user1) {
×
1137
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1138

1139
    std::unordered_set<User*> uses;
×
1140
    std::unordered_set<User*> visited;
×
1141
    std::list<User*> queue = {&user1};
×
1142
    while (!queue.empty()) {
×
1143
        auto current = queue.front();
×
1144
        queue.pop_front();
×
1145
        if (visited.find(current) != visited.end()) {
×
1146
            continue;
×
1147
        }
1148
        visited.insert(current);
×
1149

1150
        if (current != &user1) {
×
1151
            uses.insert(current);
×
1152
        }
×
1153

1154
        if (current == exit_) {
×
1155
            continue;
×
1156
        }
1157

1158
        // Extend search
1159
        auto [eb, ee] = boost::out_edges(current->vertex_, this->users_.graph_);
×
1160
        auto edges = std::ranges::subrange(eb, ee);
×
1161
        for (auto edge : edges) {
×
1162
            auto v = boost::target(edge, this->users_.graph_);
×
1163
            queue.push_back(this->users_.users_.at(v).get());
×
1164
        }
1165
    }
1166

1167
    return uses;
×
1168
};
×
1169

1170
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::read_subsets() {
6✔
1171
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
6✔
1172
    for (auto& read : this->sub_users_) {
50✔
1173
        if (read->use() != Use::READ) {
44✔
1174
            continue;
24✔
1175
        }
1176

1177
        auto& data = read->container();
20✔
1178
        if (readset.find(data) == readset.end()) {
20✔
1179
            readset[data] = std::vector<data_flow::Subset>();
14✔
1180
        }
14✔
1181
        auto& subsets = read->subsets();
20✔
1182
        for (auto& subset : subsets) {
40✔
1183
            readset[data].push_back(subset);
20✔
1184
        }
1185
    }
20✔
1186
    return readset;
6✔
1187
};
6✔
1188

1189
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::write_subsets() {
6✔
1190
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
6✔
1191
    for (auto& write : this->sub_users_) {
50✔
1192
        if (write->use() != Use::WRITE) {
44✔
1193
            continue;
36✔
1194
        }
1195

1196
        auto& data = write->container();
8✔
1197
        if (writeset.find(data) == writeset.end()) {
8✔
1198
            writeset[data] = std::vector<data_flow::Subset>();
8✔
1199
        }
8✔
1200
        auto& subsets = write->subsets();
8✔
1201
        for (auto& subset : subsets) {
16✔
1202
            writeset[data].push_back(subset);
8✔
1203
        }
1204
    }
8✔
1205
    return writeset;
6✔
1206
};
6✔
1207

1208
std::unordered_set<std::string> UsersView::locals(StructuredSDFG& sdfg,
106✔
1209
                                                  structured_control_flow::ControlFlowNode& node) {
1210
    // Collect all node elements
1211
    Users local_users(sdfg, node);
106✔
1212
    analysis::AnalysisManager analysis_manager(users_.sdfg_);
106✔
1213
    local_users.run(analysis_manager);
106✔
1214
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
106✔
1215
    for (auto& entry : local_users.users_) {
2,002✔
1216
        if (entry.second->use() == Use::NOP) {
1,896✔
1217
            continue;
604✔
1218
        }
1219
        if (!sdfg.is_transient(entry.second->container())) {
1,292✔
1220
            continue;
320✔
1221
        }
1222

1223
        if (elements.find(entry.second->container()) == elements.end()) {
972✔
1224
            elements[entry.second->container()] = {};
266✔
1225
        }
266✔
1226
        elements[entry.second->container()].insert(entry.second->element());
972✔
1227
    }
1228

1229
    // Determine locals
1230
    for (auto& entry : this->sub_users_) {
5,264✔
1231
        if (entry->use() == Use::NOP) {
5,158✔
1232
            continue;
1,532✔
1233
        }
1234

1235
        auto& container = entry->container();
3,626✔
1236
        auto element = entry->element();
3,626✔
1237
        if (elements.find(container) == elements.end()) {
3,626✔
1238
            continue;
2,729✔
1239
        }
1240
        // used outside of node
1241
        if (elements[container].find(element) == elements[container].end()) {
897✔
1242
            elements.erase(container);
138✔
1243
        }
138✔
1244
    }
1245

1246
    std::unordered_set<std::string> locals;
106✔
1247
    for (auto& entry : elements) {
234✔
1248
        locals.insert(entry.first);
128✔
1249
    }
1250
    return locals;
106✔
1251
};
106✔
1252

1253
User* Users::get_user(const std::string& container, Element* element, Use use, bool is_init,
308✔
1254
                      bool is_condition, bool is_update) {
1255
    if (auto for_loop = dynamic_cast<structured_control_flow::For*>(element)) {
308✔
1256
        if (is_init) {
38✔
1257
            auto tmp = users_by_sdfg_loop_init_.at(container).at(for_loop).at(use);
10✔
1258
            return tmp;
10✔
1259
        } else if (is_condition) {
28✔
1260
            return users_by_sdfg_loop_condition_.at(container).at(for_loop).at(use);
10✔
1261
        } else if (is_update) {
18✔
1262
            return users_by_sdfg_loop_update_.at(container).at(for_loop).at(use);
18✔
1263
        }
1264
    }
×
1265
    auto tmp = users_by_sdfg_.at(container).at(element).at(use);
270✔
1266
    return tmp;
270✔
1267
}
308✔
1268

1269
void Users::add_user(std::unique_ptr<User> user) {
18,414✔
1270
    auto vertex = user->vertex_;
18,414✔
1271
    this->users_.insert({vertex, std::move(user)});
18,414✔
1272

1273
    auto user_ptr = this->users_.at(vertex).get();
18,414✔
1274
    auto* target_structure = &users_by_sdfg_;
18,414✔
1275
    if (auto for_user = dynamic_cast<ForUser*>(user_ptr)) {
18,414✔
1276
        auto for_loop = dynamic_cast<structured_control_flow::For*>(user_ptr->element());
6,004✔
1277
        assert(for_loop != nullptr);
6,004✔
1278
        if (for_user->is_init()) {
6,004✔
1279
            target_structure = &users_by_sdfg_loop_init_;
1,397✔
1280
        } else if (for_user->is_condition()) {
6,004✔
1281
            target_structure = &users_by_sdfg_loop_condition_;
2,283✔
1282
        } else if (for_user->is_update()) {
4,607✔
1283
            target_structure = &users_by_sdfg_loop_update_;
2,324✔
1284
        } else {
2,324✔
1285
            assert(false);
×
1286
        }
1287
    }
6,004✔
1288

1289
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
18,414✔
1290
        target_structure->insert({user_ptr->container(), {}});
9,141✔
1291
    }
9,141✔
1292
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
36,828✔
1293
        (*target_structure)[user_ptr->container()].end()) {
18,414✔
1294
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
16,940✔
1295
    }
16,940✔
1296
    auto res = target_structure->at(user_ptr->container())
18,414✔
1297
                   .at(user_ptr->element())
18,414✔
1298
                   .insert({user_ptr->use(), user_ptr});
18,414✔
1299
    assert(res.second);
18,414✔
1300
}
18,414✔
1301

1302
}  // namespace analysis
1303
}  // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc