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

daisytuner / sdfglib / 15518226219

08 Jun 2025 12:03PM UTC coverage: 61.652% (-0.8%) from 62.447%
15518226219

push

github

web-flow
Merge pull request #65 from daisytuner/lib-nodes-plugins

Adds registry for library node dispatchers

41 of 77 new or added lines in 5 files covered. (53.25%)

124 existing lines in 10 files now uncovered.

7249 of 11758 relevant lines covered (61.65%)

125.57 hits per line

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

63.46
/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/map.h"
16
#include "sdfg/structured_control_flow/sequence.h"
17
#include "sdfg/structured_sdfg.h"
18
#include "sdfg/symbolic/symbolic.h"
19

20
namespace sdfg {
21
namespace analysis {
22

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

26
      };
2,578✔
27

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

32
      };
1,192✔
33

34
User::~User() {
6,776✔
35

36
};
6,776✔
37

38
Use User::use() const { return this->use_; };
16,350✔
39

40
std::string& User::container() { return this->container_; };
26,896✔
41

42
Element* User::element() { return this->element_; };
9,793✔
43

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

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

51
    if (auto access_node = dynamic_cast<data_flow::AccessNode*>(this->element_)) {
343✔
52
        auto& graph = *this->parent_;
343✔
53
        if (this->use_ == Use::READ || this->use_ == Use::VIEW) {
343✔
54
            std::vector<data_flow::Subset> subsets;
89✔
55
            for (auto& iedge : graph.out_edges(*access_node)) {
186✔
56
                subsets.push_back(iedge.subset());
97✔
57
            }
58
            return subsets;
89✔
59
        } else if (this->use_ == Use::WRITE || this->use_ == Use::MOVE) {
343✔
60
            std::vector<data_flow::Subset> subsets;
254✔
61
            for (auto& oedge : graph.in_edges(*access_node)) {
508✔
62
                subsets.push_back(oedge.subset());
254✔
63
            }
64
            return subsets;
254✔
65
        }
254✔
66
    }
×
67

68
    // Use of symbol
69
    return {{sdfg::symbolic::integer(0)}};
×
70
};
343✔
71

72
ForUser::ForUser(graph::Vertex vertex, const std::string& container, Element* element, Use use,
764✔
73
                 bool is_init, bool is_condition, bool is_update)
74
    : User(vertex, container, element, use),
764✔
75
      is_init_(is_init),
764✔
76
      is_condition_(is_condition),
764✔
77
      is_update_(is_update) {
1,528✔
78

79
      };
764✔
80

81
bool ForUser::is_init() const { return this->is_init_; };
768✔
82

83
bool ForUser::is_condition() const { return this->is_condition_; };
583✔
84

85
bool ForUser::is_update() const { return this->is_update_; };
282✔
86

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

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

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

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

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

133
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
249✔
134
                        boost::add_edge(last, v, this->graph_);
244✔
135
                    } else {
244✔
136
                        first = v;
5✔
137
                    }
138
                    last = v;
249✔
139
                }
249✔
140
                if (dataflow.out_degree(*access_node) > 0) {
523✔
141
                    Use use = Use::READ;
281✔
142
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
573✔
143
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
294✔
144
                            use = Use::VIEW;
2✔
145
                            break;
2✔
146
                        }
147
                    }
148

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

153
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
281✔
154
                        boost::add_edge(last, v, this->graph_);
64✔
155
                    } else {
64✔
156
                        first = v;
217✔
157
                    }
158
                    last = v;
281✔
159
                }
281✔
160
            }
523✔
161
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
772✔
162
            if (tasklet->is_conditional()) {
247✔
163
                auto& condition = tasklet->condition();
12✔
164
                for (auto& atom : symbolic::atoms(condition)) {
24✔
165
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
12✔
166
                    auto v = boost::add_vertex(this->graph_);
12✔
167
                    this->add_user(
12✔
168
                        std::make_unique<User>(v, sym->get_name(), tasklet, &dataflow, Use::READ));
12✔
169
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
12✔
170
                        boost::add_edge(last, v, this->graph_);
6✔
171
                    } else {
6✔
172
                        first = v;
6✔
173
                    }
174
                    last = v;
12✔
175
                }
12✔
176
            }
12✔
177
        }
247✔
178

179
        for (auto& oedge : dataflow.out_edges(*node)) {
1,313✔
180
            std::unordered_set<std::string> used;
541✔
181
            for (auto dim : oedge.subset()) {
1,002✔
182
                for (auto atom : symbolic::atoms(dim)) {
1,111✔
183
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
650✔
184
                    if (used.find(sym->get_name()) != used.end()) {
650✔
185
                        continue;
×
186
                    }
187
                    used.insert(sym->get_name());
650✔
188

189
                    auto v = boost::add_vertex(this->graph_);
650✔
190
                    this->add_user(
650✔
191
                        std::make_unique<User>(v, sym->get_name(), &oedge, &dataflow, Use::READ));
650✔
192
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
650✔
193
                        boost::add_edge(last, v, this->graph_);
640✔
194
                    } else {
640✔
195
                        first = v;
10✔
196
                    }
197
                    last = v;
650✔
198
                }
650✔
199
            }
461✔
200
        }
541✔
201
    }
202

203
    return {first, last};
311✔
204
};
×
205

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

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

219
        auto& dataflow = block_stmt->dataflow();
311✔
220
        auto subgraph = this->traverse(dataflow);
311✔
221

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

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

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

237
        graph::Vertex current = s;
370✔
238
        for (size_t i = 0; i < sequence_stmt->size(); i++) {
858✔
239
            auto child = sequence_stmt->at(i);
488✔
240

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

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

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

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

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

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

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

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

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

293
        graph::Vertex last = s;
18✔
294

295
        std::unordered_set<std::string> used;
18✔
296
        for (size_t i = 0; i < if_else_stmt->size(); i++) {
53✔
297
            auto& condition = if_else_stmt->at(i).second;
35✔
298
            for (auto atom : symbolic::atoms(condition)) {
66✔
299
                auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
31✔
300
                if (used.find(sym->get_name()) != used.end()) {
31✔
301
                    continue;
15✔
302
                }
303
                used.insert(sym->get_name());
16✔
304

305
                auto v = boost::add_vertex(this->graph_);
16✔
306

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

309
                boost::add_edge(last, v, this->graph_);
16✔
310
                last = v;
16✔
311
            }
31✔
312
        }
35✔
313

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

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

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

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

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

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

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

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

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

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

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

384
        boost::add_edge(last, v, this->graph_);
138✔
385
        last = v;
138✔
386

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

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

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

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

413
        auto update_v = boost::add_vertex(this->graph_);
138✔
414
        this->add_user(std::make_unique<ForUser>(update_v, for_stmt->indvar()->get_name(), for_stmt,
276✔
415
                                                 Use::WRITE, false, false, true));
138✔
416

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

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

426
        // Back edge
427
        boost::add_edge(t, last, this->graph_);
138✔
428

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

457
        // Indvar
458
        auto v = boost::add_vertex(this->graph_);
1✔
459
        this->add_user(
1✔
460
            std::make_unique<User>(v, map_stmt->indvar()->get_name(), map_stmt, Use::WRITE));
1✔
461
        boost::add_edge(last, v, this->graph_);
1✔
462
        last = v;
1✔
463

464
        // Root
465
        auto subgraph = this->traverse(map_stmt->root());
1✔
466
        boost::add_edge(last, subgraph.first, this->graph_);
1✔
467

468
        // NOP
469
        auto t = boost::add_vertex(this->graph_);
1✔
470
        this->users_.insert({t, std::make_unique<User>(t, "", map_stmt, Use::NOP)});
1✔
471
        last = t;
1✔
472
        boost::add_edge(subgraph.second, last, this->graph_);
1✔
473
        this->exits_.insert({map_stmt, this->users_.at(t).get()});
1✔
474

475
        return {s, t};
1✔
476
    }
477

478
    throw std::invalid_argument("Invalid control flow node type");
×
479
};
858✔
480

481
Users::Users(StructuredSDFG& sdfg)
115✔
482
    : Analysis(sdfg), node_(sdfg.root()) {
115✔
483

484
      };
115✔
485

486
Users::Users(StructuredSDFG& sdfg, structured_control_flow::ControlFlowNode& node)
142✔
487
    : Analysis(sdfg), node_(node) {
71✔
488

489
      };
71✔
490

491
void Users::run(analysis::AnalysisManager& analysis_manager) {
186✔
492
    users_.clear();
186✔
493
    graph_.clear();
186✔
494
    source_ = nullptr;
186✔
495
    sink_ = nullptr;
186✔
496
    dom_tree_.clear();
186✔
497
    pdom_tree_.clear();
186✔
498
    users_by_sdfg_.clear();
186✔
499
    users_by_sdfg_loop_condition_.clear();
186✔
500
    users_by_sdfg_loop_init_.clear();
186✔
501
    users_by_sdfg_loop_update_.clear();
186✔
502

503
    reads_.clear();
186✔
504
    writes_.clear();
186✔
505
    views_.clear();
186✔
506
    moves_.clear();
186✔
507

508
    this->traverse(node_);
186✔
509
    if (this->users_.empty()) {
186✔
510
        return;
×
511
    }
512

513
    // Require a single source
514
    for (auto& entry : this->users_) {
3,956✔
515
        if (boost::in_degree(entry.first, this->graph_) == 0) {
3,770✔
516
            if (this->source_ != nullptr) {
186✔
517
                throw InvalidSDFGException("Users Analysis: Non-unique source node");
×
518
            }
519
            this->source_ = entry.second.get();
186✔
520
        }
186✔
521
    }
522
    if (this->source_ == nullptr) {
186✔
523
        throw InvalidSDFGException("Users Analysis: No source node");
×
524
    }
525

526
    std::list<User*> sinks;
186✔
527
    for (auto& entry : this->users_) {
3,956✔
528
        if (boost::out_degree(entry.first, this->graph_) == 0) {
3,770✔
529
            sinks.push_back(entry.second.get());
186✔
530
        }
186✔
531
    }
532
    if (sinks.size() == 0) {
186✔
533
        throw InvalidSDFGException("Users Analysis: No sink node");
×
534
    }
535
    if (sinks.size() > 1) {
186✔
536
        // add artificial sink
537
        auto v = boost::add_vertex(this->graph_);
×
538
        auto sink = std::make_unique<User>(v, "", nullptr, Use::NOP);
×
539
        this->users_.insert({v, std::move(sink)});
×
540
        for (auto sink : sinks) {
×
541
            boost::add_edge(sink->vertex_, v, this->graph_);
×
542
        }
543
        sinks.clear();
×
544

545
        this->sink_ = this->users_.at(v).get();
×
546
    } else {
×
547
        this->sink_ = sinks.front();
186✔
548
    }
549

550
    // Collect sub structures
551
    for (auto& entry : this->users_) {
3,956✔
552
        auto container = entry.second->container();
3,770✔
553
        switch (entry.second->use()) {
3,770✔
554
            case Use::READ: {
555
                if (this->reads_.find(container) == this->reads_.end()) {
1,472✔
556
                    this->reads_.insert({container, {}});
642✔
557
                }
642✔
558
                this->reads_[container].push_back(entry.second.get());
1,472✔
559
                break;
1,472✔
560
            }
561
            case Use::WRITE: {
562
                if (this->writes_.find(container) == this->writes_.end()) {
588✔
563
                    this->writes_.insert({container, {}});
396✔
564
                }
396✔
565
                this->writes_[container].push_back(entry.second.get());
588✔
566
                break;
588✔
567
            }
568
            case Use::VIEW: {
569
                if (this->views_.find(container) == this->views_.end()) {
2✔
570
                    this->views_.insert({container, {}});
2✔
571
                }
2✔
572
                this->views_[container].push_back(entry.second.get());
2✔
573
                break;
2✔
574
            }
575
            case Use::MOVE: {
576
                if (this->moves_.find(container) == this->moves_.end()) {
2✔
577
                    this->moves_.insert({container, {}});
2✔
578
                }
2✔
579
                this->moves_[container].push_back(entry.second.get());
2✔
580
                break;
2✔
581
            }
582
            default:
583
                break;
1,706✔
584
        }
585
    }
3,770✔
586
};
186✔
587

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

597
    return us;
×
598
};
×
599

600
std::vector<User*> Users::uses(const std::string& container) const {
1✔
601
    std::vector<User*> us;
1✔
602
    for (auto& entry : this->users_) {
10✔
603
        if (entry.second->container() != container) {
9✔
604
            continue;
7✔
605
        }
606
        if (entry.second->use() == Use::NOP) {
2✔
607
            continue;
×
608
        }
609
        us.push_back(entry.second.get());
2✔
610
    }
611

612
    return us;
1✔
613
};
1✔
614

615
std::vector<User*> Users::writes() const {
×
616
    std::vector<User*> us;
×
617
    for (auto& entry : this->users_) {
×
618
        if (entry.second->use() != Use::WRITE) {
×
619
            continue;
×
620
        }
621
        us.push_back(entry.second.get());
×
622
    }
623

624
    return us;
×
625
};
×
626

627
std::vector<User*> Users::writes(const std::string& container) const {
48✔
628
    if (this->writes_.find(container) == this->writes_.end()) {
48✔
629
        return {};
25✔
630
    } else {
631
        return this->writes_.at(container);
23✔
632
    }
633
};
48✔
634

635
std::vector<User*> Users::reads() const {
×
636
    std::vector<User*> us;
×
637
    for (auto& entry : this->users_) {
×
638
        if (entry.second->use() != Use::READ) {
×
639
            continue;
×
640
        }
641
        us.push_back(entry.second.get());
×
642
    }
643

644
    return us;
×
645
};
×
646

647
std::vector<User*> Users::reads(const std::string& container) const {
33✔
648
    if (this->reads_.find(container) == this->reads_.end()) {
33✔
649
        return {};
13✔
650
    } else {
651
        return this->reads_.at(container);
20✔
652
    }
653
};
33✔
654

655
std::vector<User*> Users::views() const {
×
656
    std::vector<User*> us;
×
657
    for (auto& entry : this->users_) {
×
658
        if (entry.second->use() != Use::VIEW) {
×
659
            continue;
×
660
        }
661
        us.push_back(entry.second.get());
×
662
    }
663

664
    return us;
×
665
};
×
666

667
std::vector<User*> Users::views(const std::string& container) const {
53✔
668
    if (this->views_.find(container) == this->views_.end()) {
53✔
669
        return {};
53✔
670
    } else {
671
        return this->views_.at(container);
×
672
    }
673
};
53✔
674

675
std::vector<User*> Users::moves() const {
×
676
    std::vector<User*> us;
×
677
    for (auto& entry : this->users_) {
×
678
        if (entry.second->use() != Use::MOVE) {
×
679
            continue;
×
680
        }
681
        us.push_back(entry.second.get());
×
682
    }
683

684
    return us;
×
685
};
×
686

687
std::vector<User*> Users::moves(const std::string& container) const {
53✔
688
    if (this->moves_.find(container) == this->moves_.end()) {
53✔
689
        return {};
52✔
690
    } else {
691
        return this->moves_.at(container);
1✔
692
    }
693
};
53✔
694

695
/****** Domination Analysis ******/
696

697
const std::unordered_map<User*, User*>& Users::dominator_tree() {
×
698
    if (this->dom_tree_.empty()) {
×
699
        this->init_dom_tree();
×
700
    }
×
701
    return this->dom_tree_;
×
702
};
703

704
bool Users::dominates(User& user1, User& user) {
26✔
705
    if (this->dom_tree_.empty()) {
26✔
706
        this->init_dom_tree();
19✔
707
    }
19✔
708
    auto dominator = this->dom_tree_.at(&user);
26✔
709
    while (dominator != nullptr) {
88✔
710
        if (dominator == &user1) {
88✔
711
            return true;
26✔
712
        }
713
        dominator = this->dom_tree_.at(dominator);
62✔
714
    }
715
    return false;
×
716
};
26✔
717

718
const std::unordered_map<User*, User*>& Users::post_dominator_tree() {
×
719
    if (this->pdom_tree_.empty()) {
×
720
        this->init_dom_tree();
×
721
    }
×
722
    return this->pdom_tree_;
×
723
};
724

725
bool Users::post_dominates(User& user1, User& user) {
6✔
726
    if (this->pdom_tree_.empty()) {
6✔
727
        this->init_dom_tree();
×
728
    }
×
729
    auto dominator = this->pdom_tree_.at(&user);
6✔
730
    while (dominator != nullptr) {
12✔
731
        if (dominator == &user1) {
12✔
732
            return true;
6✔
733
        }
734
        dominator = this->pdom_tree_.at(dominator);
6✔
735
    }
736
    return false;
×
737
};
6✔
738

739
const std::unordered_set<User*> Users::all_uses_between(User& user1, User& user) {
91✔
740
    std::unordered_set<User*> uses;
91✔
741
    std::unordered_set<User*> visited;
91✔
742
    std::list<User*> queue = {&user};
91✔
743
    while (!queue.empty()) {
2,023✔
744
        auto current = queue.front();
1,932✔
745
        queue.pop_front();
1,932✔
746

747
        // Stop conditions
748
        if (current == &user1) {
1,932✔
749
            continue;
91✔
750
        }
751

752
        if (visited.find(current) != visited.end()) {
1,841✔
753
            continue;
197✔
754
        }
755
        visited.insert(current);
1,644✔
756

757
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
1,644✔
758
            uses.insert(current);
1,040✔
759
        }
1,040✔
760

761
        // Extend search
762
        // Backward search to utilize domination user1 over user
763
        auto [eb, ee] = boost::in_edges(current->vertex_, this->graph_);
1,644✔
764
        auto edges = std::ranges::subrange(eb, ee);
3,288✔
765
        for (auto edge : edges) {
3,485✔
766
            auto v = boost::source(edge, this->graph_);
1,841✔
767
            queue.push_back(this->users_.at(v).get());
1,841✔
768
        }
769
    }
770

771
    return uses;
91✔
772
};
91✔
773

774
const std::unordered_set<User*> Users::all_uses_after(User& user1) {
×
775
    std::unordered_set<User*> uses;
×
776
    std::unordered_set<User*> visited;
×
777
    std::list<User*> queue = {&user1};
×
778
    while (!queue.empty()) {
×
779
        auto current = queue.front();
×
780
        queue.pop_front();
×
781
        if (visited.find(current) != visited.end()) {
×
782
            continue;
×
783
        }
784
        visited.insert(current);
×
785

786
        if (current != &user1 && current->use() != Use::NOP) {
×
787
            uses.insert(current);
×
788
        }
×
789

790
        // Extend search
791
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
792
        auto edges = std::ranges::subrange(eb, ee);
×
793
        for (auto edge : edges) {
×
794
            auto v = boost::target(edge, this->graph_);
×
795
            queue.push_back(this->users_.at(v).get());
×
796
        }
797
    }
798

799
    return uses;
×
800
};
×
801

802
const std::unordered_set<User*> Users::sources(const std::string& container) const {
×
803
    auto source = this->source_;
×
804

805
    std::unordered_set<User*> sources;
×
806
    std::unordered_set<User*> visited;
×
807
    std::list<User*> queue = {source};
×
808
    while (!queue.empty()) {
×
809
        auto current = queue.front();
×
810
        queue.pop_front();
×
811
        if (visited.find(current) != visited.end()) {
×
812
            continue;
×
813
        }
814
        visited.insert(current);
×
815

816
        if (current->container() == container && current->use() != Use::NOP) {
×
817
            sources.insert(current);
×
818
            continue;
×
819
        }
820

821
        // Extend search
822
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
823
        auto edges = std::ranges::subrange(eb, ee);
×
824
        for (auto edge : edges) {
×
825
            auto v = boost::target(edge, this->graph_);
×
826
            queue.push_back(this->users_.at(v).get());
×
827
        }
828
    }
829

830
    return sources;
×
831
};
×
832

833
/****** Happens-Before Analysis ******/
834

835
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::read_subsets() {
×
836
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
×
837
    for (auto& read : this->users_) {
×
838
        if (read.second->use() != Use::READ) {
×
839
            continue;
×
840
        }
841

842
        auto& data = read.second->container();
×
843
        if (readset.find(data) == readset.end()) {
×
844
            readset[data] = std::vector<data_flow::Subset>();
×
845
        }
×
846
        auto& subsets = read.second->subsets();
×
847
        for (auto& subset : subsets) {
×
848
            readset[data].push_back(subset);
×
849
        }
850
    }
×
851
    return readset;
×
852
};
×
853

854
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::write_subsets() {
×
855
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
856
    for (auto& write : this->users_) {
×
857
        if (write.second->use() != Use::WRITE) {
×
858
            continue;
×
859
        }
860

861
        auto& data = write.second->container();
×
862
        if (writeset.find(data) == writeset.end()) {
×
863
            writeset[data] = std::vector<data_flow::Subset>();
×
864
        }
×
865
        auto& subsets = write.second->subsets();
×
866
        for (auto& subset : subsets) {
×
867
            writeset[data].push_back(subset);
×
868
        }
869
    }
×
870
    return writeset;
×
871
};
×
872

873
std::unordered_set<std::string> Users::locals(StructuredSDFG& sdfg,
71✔
874
                                              structured_control_flow::ControlFlowNode& node) {
875
    // Collect all node elements
876
    Users local_users(sdfg, node);
71✔
877
    analysis::AnalysisManager analysis_manager(sdfg_);
71✔
878
    local_users.run(analysis_manager);
71✔
879
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
71✔
880
    for (auto& entry : local_users.users_) {
1,682✔
881
        if (entry.second->use() == Use::NOP) {
1,611✔
882
            continue;
606✔
883
        }
884
        if (!sdfg.is_transient(entry.second->container())) {
1,005✔
885
            continue;
297✔
886
        }
887

888
        if (elements.find(entry.second->container()) == elements.end()) {
708✔
889
            elements[entry.second->container()] = {};
202✔
890
        }
202✔
891
        elements[entry.second->container()].insert(entry.second->element());
708✔
892
    }
893

894
    // Determine locals
895
    for (auto& entry : this->users_) {
2,949✔
896
        if (entry.second->use() == Use::NOP) {
2,878✔
897
            continue;
1,140✔
898
        }
899

900
        auto& container = entry.second->container();
1,738✔
901
        auto element = entry.second->element();
1,738✔
902
        if (elements.find(container) == elements.end()) {
1,738✔
903
            continue;
1,164✔
904
        }
905
        // used outside of node
906
        if (elements[container].find(element) == elements[container].end()) {
574✔
907
            elements.erase(container);
101✔
908
        }
101✔
909
    }
910

911
    std::unordered_set<std::string> locals;
71✔
912
    for (auto& entry : elements) {
172✔
913
        locals.insert(entry.first);
101✔
914
    }
915
    return locals;
71✔
916
};
71✔
917

918
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
77✔
919
    auto& entry = users.entries_.at(&node);
77✔
920
    auto& exit = users.exits_.at(&node);
77✔
921
    this->entry_ = entry;
77✔
922
    this->exit_ = exit;
77✔
923
    this->sub_users_ = users.all_uses_between(*entry, *exit);
77✔
924
};
77✔
925

926
std::vector<User*> UsersView::uses() const {
×
927
    std::vector<User*> us;
×
928
    for (auto& user : this->sub_users_) {
×
929
        if (user->use() == Use::NOP) {
×
930
            continue;
×
931
        }
932
        us.push_back(user);
×
933
    }
934

935
    return us;
×
936
};
×
937

938
std::vector<User*> UsersView::uses(const std::string& container) const {
9✔
939
    std::vector<User*> us;
9✔
940
    for (auto& user : this->sub_users_) {
51✔
941
        if (user->container() != container) {
42✔
942
            continue;
26✔
943
        }
944
        if (user->use() == Use::NOP) {
16✔
945
            continue;
×
946
        }
947
        us.push_back(user);
16✔
948
    }
949

950
    return us;
9✔
951
};
9✔
952

953
std::vector<User*> UsersView::writes() const {
73✔
954
    std::vector<User*> us;
73✔
955
    for (auto& user : this->sub_users_) {
1,088✔
956
        if (user->use() != Use::WRITE) {
1,015✔
957
            continue;
783✔
958
        }
959
        us.push_back(user);
232✔
960
    }
961

962
    return us;
73✔
963
};
73✔
964

965
std::vector<User*> UsersView::writes(const std::string& container) const {
91✔
966
    std::vector<User*> us;
91✔
967
    for (auto& user : this->sub_users_) {
2,426✔
968
        if (user->container() != container) {
2,335✔
969
            continue;
2,161✔
970
        }
971
        if (user->use() != Use::WRITE) {
174✔
972
            continue;
79✔
973
        }
974
        us.push_back(user);
95✔
975
    }
976

977
    return us;
91✔
978
};
91✔
979

980
std::vector<User*> UsersView::reads() const {
70✔
981
    std::vector<User*> us;
70✔
982
    for (auto& user : this->sub_users_) {
1,074✔
983
        if (user->use() != Use::READ) {
1,004✔
984
            continue;
230✔
985
        }
986
        us.push_back(user);
774✔
987
    }
988

989
    return us;
70✔
990
};
70✔
991

992
std::vector<User*> UsersView::reads(const std::string& container) const {
75✔
993
    std::vector<User*> us;
75✔
994
    for (auto& user : this->sub_users_) {
2,241✔
995
        if (user->container() != container) {
2,166✔
996
            continue;
2,021✔
997
        }
998
        if (user->use() != Use::READ) {
145✔
999
            continue;
79✔
1000
        }
1001
        us.push_back(user);
66✔
1002
    }
1003

1004
    return us;
75✔
1005
};
75✔
1006

1007
std::vector<User*> UsersView::views() const {
70✔
1008
    std::vector<User*> us;
70✔
1009
    for (auto& user : this->sub_users_) {
1,074✔
1010
        if (user->use() != Use::VIEW) {
1,004✔
1011
            continue;
1,004✔
1012
        }
1013
        us.push_back(user);
×
1014
    }
1015

1016
    return us;
70✔
1017
};
70✔
1018

UNCOV
1019
std::vector<User*> UsersView::views(const std::string& container) const {
×
UNCOV
1020
    std::vector<User*> us;
×
UNCOV
1021
    for (auto& user : this->sub_users_) {
×
UNCOV
1022
        if (user->container() != container) {
×
UNCOV
1023
            continue;
×
1024
        }
UNCOV
1025
        if (user->use() != Use::VIEW) {
×
UNCOV
1026
            continue;
×
1027
        }
1028
        us.push_back(user);
×
1029
    }
1030

UNCOV
1031
    return us;
×
UNCOV
1032
};
×
1033

1034
std::vector<User*> UsersView::moves() const {
70✔
1035
    std::vector<User*> us;
70✔
1036
    for (auto& user : this->sub_users_) {
1,074✔
1037
        if (user->use() != Use::MOVE) {
1,004✔
1038
            continue;
1,004✔
1039
        }
1040
        us.push_back(user);
×
1041
    }
1042

1043
    return us;
70✔
1044
};
70✔
1045

UNCOV
1046
std::vector<User*> UsersView::moves(const std::string& container) const {
×
UNCOV
1047
    std::vector<User*> us;
×
UNCOV
1048
    for (auto& user : this->sub_users_) {
×
UNCOV
1049
        if (user->container() != container) {
×
UNCOV
1050
            continue;
×
1051
        }
UNCOV
1052
        if (user->use() != Use::MOVE) {
×
UNCOV
1053
            continue;
×
1054
        }
1055
        us.push_back(user);
×
1056
    }
1057

UNCOV
1058
    return us;
×
UNCOV
1059
};
×
1060

1061
std::unordered_map<User*, User*> UsersView::dominator_tree() {
×
1062
    if (!this->sub_dom_tree_.empty()) {
×
1063
        return this->sub_dom_tree_;
×
1064
    }
1065

1066
    auto dom_tree = this->users_.dominator_tree();
×
1067
    std::unordered_map<User*, User*> sub_dom_tree;
×
1068
    for (auto& entry : this->sub_users_) {
×
1069
        sub_dom_tree[entry] = dom_tree[entry];
×
1070
    }
1071
    sub_dom_tree[this->entry_] = nullptr;
×
1072
    return sub_dom_tree;
×
1073
};
×
1074

1075
bool UsersView::dominates(User& user1, User& user) {
×
1076
    auto dom_tree = this->dominator_tree();
×
1077
    auto dominator = dom_tree[&user];
×
1078
    while (dominator != nullptr) {
×
1079
        if (dominator == &user1) {
×
1080
            return true;
×
1081
        }
1082
        dominator = dom_tree[dominator];
×
1083
    }
1084
    return false;
×
1085
};
×
1086

1087
std::unordered_map<User*, User*> UsersView::post_dominator_tree() {
×
1088
    if (!this->sub_pdom_tree_.empty()) {
×
1089
        return this->sub_pdom_tree_;
×
1090
    }
1091

1092
    auto pdom_tree = this->users_.post_dominator_tree();
×
1093
    std::unordered_map<User*, User*> sub_pdom_tree;
×
1094
    for (auto& entry : this->sub_users_) {
×
1095
        sub_pdom_tree[entry] = pdom_tree[entry];
×
1096
    }
1097
    sub_pdom_tree[this->exit_] = nullptr;
×
1098
    return sub_pdom_tree;
×
1099
};
×
1100

1101
bool UsersView::post_dominates(User& user1, User& user) {
×
1102
    auto pdom_tree = this->post_dominator_tree();
×
1103
    auto dominator = pdom_tree[&user];
×
1104
    while (dominator != nullptr) {
×
1105
        if (dominator == &user1) {
×
1106
            return true;
×
1107
        }
1108
        dominator = pdom_tree[dominator];
×
1109
    }
1110
    return false;
×
1111
};
×
1112

1113
std::unordered_set<User*> UsersView::all_uses_between(User& user1, User& user) {
×
1114
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1115
    assert(this->sub_users_.find(&user) != this->sub_users_.end());
×
1116

1117
    std::unordered_set<User*> uses;
×
1118
    std::unordered_set<User*> visited;
×
1119
    std::list<User*> queue = {&user1};
×
1120
    while (!queue.empty()) {
×
1121
        auto current = queue.front();
×
1122
        queue.pop_front();
×
1123
        if (visited.find(current) != visited.end()) {
×
1124
            continue;
×
1125
        }
1126
        visited.insert(current);
×
1127

1128
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
×
1129
            uses.insert(current);
×
1130
        }
×
1131

1132
        // Stop conditions
1133
        if (current == exit_) {
×
1134
            continue;
×
1135
        }
1136

1137
        if (current == &user) {
×
1138
            continue;
×
1139
        }
1140

1141
        // Extend search
1142
        auto [eb, ee] = boost::out_edges(current->vertex_, this->users_.graph_);
×
1143
        auto edges = std::ranges::subrange(eb, ee);
×
1144
        for (auto edge : edges) {
×
1145
            auto v = boost::target(edge, this->users_.graph_);
×
1146
            queue.push_back(this->users_.users_.at(v).get());
×
1147
        }
1148
    }
1149

1150
    return uses;
×
1151
};
×
1152

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

1156
    std::unordered_set<User*> uses;
×
1157
    std::unordered_set<User*> visited;
×
1158
    std::list<User*> queue = {&user1};
×
1159
    while (!queue.empty()) {
×
1160
        auto current = queue.front();
×
1161
        queue.pop_front();
×
1162
        if (visited.find(current) != visited.end()) {
×
1163
            continue;
×
1164
        }
1165
        visited.insert(current);
×
1166

1167
        if (current != &user1 && current->use() != Use::NOP) {
×
1168
            uses.insert(current);
×
1169
        }
×
1170

1171
        if (current == exit_) {
×
1172
            continue;
×
1173
        }
1174

1175
        // Extend search
1176
        auto [eb, ee] = boost::out_edges(current->vertex_, this->users_.graph_);
×
1177
        auto edges = std::ranges::subrange(eb, ee);
×
1178
        for (auto edge : edges) {
×
1179
            auto v = boost::target(edge, this->users_.graph_);
×
1180
            queue.push_back(this->users_.users_.at(v).get());
×
1181
        }
1182
    }
1183

1184
    return uses;
×
1185
};
×
1186

1187
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::read_subsets() {
×
1188
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
×
1189
    for (auto& read : this->sub_users_) {
×
1190
        if (read->use() != Use::READ) {
×
1191
            continue;
×
1192
        }
1193

1194
        auto& data = read->container();
×
1195
        if (readset.find(data) == readset.end()) {
×
1196
            readset[data] = std::vector<data_flow::Subset>();
×
1197
        }
×
1198
        auto& subsets = read->subsets();
×
1199
        for (auto& subset : subsets) {
×
1200
            readset[data].push_back(subset);
×
1201
        }
1202
    }
×
1203
    return readset;
×
1204
};
×
1205

1206
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::write_subsets() {
×
1207
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
1208
    for (auto& write : this->sub_users_) {
×
1209
        if (write->use() != Use::WRITE) {
×
1210
            continue;
×
1211
        }
1212

1213
        auto& data = write->container();
×
1214
        if (writeset.find(data) == writeset.end()) {
×
1215
            writeset[data] = std::vector<data_flow::Subset>();
×
1216
        }
×
1217
        auto& subsets = write->subsets();
×
1218
        for (auto& subset : subsets) {
×
1219
            writeset[data].push_back(subset);
×
1220
        }
1221
    }
×
1222
    return writeset;
×
1223
};
×
1224

1225
std::unordered_set<std::string> UsersView::locals(StructuredSDFG& sdfg,
×
1226
                                                  structured_control_flow::ControlFlowNode& node) {
1227
    // Collect all node elements
1228
    Users local_users(sdfg, node);
×
1229
    analysis::AnalysisManager analysis_manager(users_.sdfg_);
×
1230
    local_users.run(analysis_manager);
×
1231
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
×
1232
    for (auto& entry : local_users.users_) {
×
1233
        if (entry.second->use() == Use::NOP) {
×
1234
            continue;
×
1235
        }
1236
        if (!sdfg.is_transient(entry.second->container())) {
×
1237
            continue;
×
1238
        }
1239

1240
        if (elements.find(entry.second->container()) == elements.end()) {
×
1241
            elements[entry.second->container()] = {};
×
1242
        }
×
1243
        elements[entry.second->container()].insert(entry.second->element());
×
1244
    }
1245

1246
    // Determine locals
1247
    for (auto& entry : this->sub_users_) {
×
1248
        if (entry->use() == Use::NOP) {
×
1249
            continue;
×
1250
        }
1251

1252
        auto& container = entry->container();
×
1253
        auto element = entry->element();
×
1254
        if (elements.find(container) == elements.end()) {
×
1255
            continue;
×
1256
        }
1257
        // used outside of node
1258
        if (elements[container].find(element) == elements[container].end()) {
×
1259
            elements.erase(container);
×
1260
        }
×
1261
    }
1262

1263
    std::unordered_set<std::string> locals;
×
1264
    for (auto& entry : elements) {
×
1265
        locals.insert(entry.first);
×
1266
    }
1267
    return locals;
×
1268
};
×
1269

1270
User* Users::get_user(const std::string& container, Element* element, Use use, bool is_init,
310✔
1271
                      bool is_condition, bool is_update) {
1272
    if (auto for_loop = dynamic_cast<structured_control_flow::For*>(element)) {
310✔
1273
        if (is_init) {
38✔
1274
            auto tmp = users_by_sdfg_loop_init_.at(container).at(for_loop).at(use);
10✔
1275
            return tmp;
10✔
1276
        } else if (is_condition) {
28✔
1277
            return users_by_sdfg_loop_condition_.at(container).at(for_loop).at(use);
10✔
1278
        } else if (is_update) {
18✔
1279
            return users_by_sdfg_loop_update_.at(container).at(for_loop).at(use);
18✔
1280
        }
1281
    }
×
1282
    auto tmp = users_by_sdfg_.at(container).at(element).at(use);
272✔
1283
    return tmp;
272✔
1284
}
310✔
1285

1286
void Users::add_user(std::unique_ptr<User> user) {
2,064✔
1287
    auto vertex = user->vertex_;
2,064✔
1288
    this->users_.insert({vertex, std::move(user)});
2,064✔
1289

1290
    auto user_ptr = this->users_.at(vertex).get();
2,064✔
1291
    auto* target_structure = &users_by_sdfg_;
2,064✔
1292
    if (auto for_user = dynamic_cast<ForUser*>(user_ptr)) {
2,064✔
1293
        auto for_loop = dynamic_cast<structured_control_flow::For*>(user_ptr->element());
764✔
1294
        if (for_loop == nullptr) {
764✔
1295
            throw std::invalid_argument("Invalid user type");
×
1296
        }
1297
        if (for_user->is_init()) {
764✔
1298
            target_structure = &users_by_sdfg_loop_init_;
184✔
1299
        } else if (for_user->is_condition()) {
764✔
1300
            target_structure = &users_by_sdfg_loop_condition_;
303✔
1301
        } else if (for_user->is_update()) {
580✔
1302
            target_structure = &users_by_sdfg_loop_update_;
277✔
1303
        } else {
277✔
1304
            throw std::invalid_argument("Invalid user type");
×
1305
        }
1306
    }
764✔
1307

1308
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
2,064✔
1309
        target_structure->insert({user_ptr->container(), {}});
1,122✔
1310
    }
1,122✔
1311
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
4,128✔
1312
        (*target_structure)[user_ptr->container()].end()) {
2,064✔
1313
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
1,917✔
1314
    }
1,917✔
1315
    target_structure->at(user_ptr->container())
2,064✔
1316
        .at(user_ptr->element())
2,064✔
1317
        .insert({user_ptr->use(), user_ptr});
2,064✔
1318
}
2,064✔
1319

1320
}  // namespace analysis
1321
}  // 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