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

daisytuner / sdfglib / 15238257521

25 May 2025 01:14PM UTC coverage: 60.342% (-0.1%) from 60.473%
15238257521

push

github

web-flow
Merge pull request #31 from daisytuner/exception-handling

Exception handling

18 of 60 new or added lines in 17 files covered. (30.0%)

1 existing line in 1 file now uncovered.

8052 of 13344 relevant lines covered (60.34%)

102.27 hits per line

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

70.5
/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)
2,846✔
23
    : vertex_(vertex), container_(container), use_(use), element_(element) {
2,846✔
24

25
      };
2,846✔
26

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

31
      };
1,334✔
32

33
User::~User() {
7,497✔
34

35
};
7,497✔
36

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

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

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

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

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

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

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

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

78
      };
863✔
79

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

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

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

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

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

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

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

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

132
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
271✔
133
                        boost::add_edge(last, v, this->graph_);
262✔
134
                    } else {
262✔
135
                        first = v;
9✔
136
                    }
137
                    last = v;
271✔
138
                }
271✔
139
                if (dataflow.out_degree(*access_node) > 0) {
566✔
140
                    Use use = Use::READ;
302✔
141
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
614✔
142
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
315✔
143
                            use = Use::VIEW;
3✔
144
                            break;
3✔
145
                        }
146
                    }
147

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

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

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

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

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

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

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

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

221
        // May be empty
222
        if (subgraph.first == boost::graph_traits<graph::Graph>::null_vertex()) {
337✔
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_);
260✔
228
        boost::add_edge(subgraph.second, t, this->graph_);
260✔
229

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

236
        graph::Vertex current = s;
406✔
237
        for (size_t i = 0; i < sequence_stmt->size(); i++) {
943✔
238
            auto child = sequence_stmt->at(i);
537✔
239

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

244
            std::unordered_set<std::string> used;
537✔
245
            for (auto& entry : child.second.assignments()) {
601✔
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()) {
601✔
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
        }
537✔
274

275
        if (current == boost::graph_traits<graph::Graph>::null_vertex()) {
406✔
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_);
406✔
281
        this->users_.insert({t, std::make_unique<User>(t, "", sequence_stmt, Use::NOP)});
406✔
282
        boost::add_edge(current, t, this->graph_);
406✔
283
        this->exits_.insert({sequence_stmt, this->users_.at(t).get()});
406✔
284

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

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

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

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

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

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

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

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

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

332
        return {s, t};
18✔
333
    } else if (auto loop_stmt = dynamic_cast<structured_control_flow::While*>(&node)) {
200✔
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)) {
172✔
358
        // NOP
359
        auto s = boost::add_vertex(this->graph_);
153✔
360
        this->users_.insert({s, std::make_unique<User>(s, "", for_stmt, Use::NOP)});
153✔
361
        auto last = s;
153✔
362
        this->entries_.insert({for_stmt, this->users_.at(s).get()});
153✔
363

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

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

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

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

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

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

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

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

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

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

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

428
        return {s, t};
153✔
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_);
×
445
        this->users_.insert({v, std::make_unique<User>(v, "", ret_stmt, Use::NOP)});
×
446
        this->entries_.insert({ret_stmt, this->users_.at(v).get()});
×
447
        this->exits_.insert({ret_stmt, this->users_.at(v).get()});
×
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
    throw std::invalid_argument("Invalid control flow node type");
×
471
};
943✔
472

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

476
      };
124✔
477

478
Users::Users(StructuredSDFG& sdfg, structured_control_flow::ControlFlowNode& node)
150✔
479
    : Analysis(sdfg), node_(node) {
75✔
480

481
      };
75✔
482

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

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

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

505
    // Require a single source
506
    for (auto& entry : this->users_) {
4,379✔
507
        if (boost::in_degree(entry.first, this->graph_) == 0) {
4,180✔
508
            if (this->source_ != nullptr) {
199✔
NEW
509
                throw InvalidSDFGException("Users Analysis: Non-unique source node");
×
510
            }
511
            this->source_ = entry.second.get();
199✔
512
        }
199✔
513
    }
514
    if (this->source_ == nullptr) {
199✔
NEW
515
        throw InvalidSDFGException("Users Analysis: No source node");
×
516
    }
517

518
    // Sink may be empty
519
    for (auto& entry : this->users_) {
4,379✔
520
        if (boost::out_degree(entry.first, this->graph_) == 0) {
4,180✔
521
            if (this->sink_ != nullptr) {
199✔
NEW
522
                throw InvalidSDFGException("Users Analysis: Non-unique sink node");
×
523
            }
524
            this->sink_ = entry.second.get();
199✔
525
        }
199✔
526
    }
527

528
    // Collect sub structures
529
    for (auto& entry : this->users_) {
4,379✔
530
        auto container = entry.second->container();
4,180✔
531
        switch (entry.second->use()) {
4,180✔
532
            case Use::READ: {
533
                if (this->reads_.find(container) == this->reads_.end()) {
1,660✔
534
                    this->reads_.insert({container, {}});
716✔
535
                }
716✔
536
                this->reads_[container].push_back(entry.second.get());
1,660✔
537
                break;
1,660✔
538
            }
539
            case Use::WRITE: {
540
                if (this->writes_.find(container) == this->writes_.end()) {
638✔
541
                    this->writes_.insert({container, {}});
431✔
542
                }
431✔
543
                this->writes_[container].push_back(entry.second.get());
638✔
544
                break;
638✔
545
            }
546
            case Use::VIEW: {
547
                if (this->views_.find(container) == this->views_.end()) {
3✔
548
                    this->views_.insert({container, {}});
3✔
549
                }
3✔
550
                this->views_[container].push_back(entry.second.get());
3✔
551
                break;
3✔
552
            }
553
            case Use::MOVE: {
554
                if (this->moves_.find(container) == this->moves_.end()) {
3✔
555
                    this->moves_.insert({container, {}});
3✔
556
                }
3✔
557
                this->moves_[container].push_back(entry.second.get());
3✔
558
                break;
3✔
559
            }
560
            default:
561
                break;
1,876✔
562
        }
563
    }
4,180✔
564
};
199✔
565

566
std::vector<User*> Users::uses() const {
×
567
    std::vector<User*> us;
×
568
    for (auto& entry : this->users_) {
×
569
        if (entry.second->use() == Use::NOP) {
×
570
            continue;
×
571
        }
572
        us.push_back(entry.second.get());
×
573
    }
574

575
    return us;
×
576
};
×
577

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

590
    return us;
1✔
591
};
1✔
592

593
std::vector<User*> Users::writes() const {
×
594
    std::vector<User*> us;
×
595
    for (auto& entry : this->users_) {
×
596
        if (entry.second->use() != Use::WRITE) {
×
597
            continue;
×
598
        }
599
        us.push_back(entry.second.get());
×
600
    }
601

602
    return us;
×
603
};
×
604

605
std::vector<User*> Users::writes(const std::string& container) const {
66✔
606
    if (this->writes_.find(container) == this->writes_.end()) {
66✔
607
        return {};
25✔
608
    } else {
609
        return this->writes_.at(container);
41✔
610
    }
611
};
66✔
612

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

622
    return us;
×
623
};
×
624

625
std::vector<User*> Users::reads(const std::string& container) const {
33✔
626
    if (this->reads_.find(container) == this->reads_.end()) {
33✔
627
        return {};
13✔
628
    } else {
629
        return this->reads_.at(container);
20✔
630
    }
631
};
33✔
632

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

642
    return us;
×
643
};
×
644

645
std::vector<User*> Users::views(const std::string& container) const {
71✔
646
    if (this->views_.find(container) == this->views_.end()) {
71✔
647
        return {};
71✔
648
    } else {
649
        return this->views_.at(container);
×
650
    }
651
};
71✔
652

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

662
    return us;
×
663
};
×
664

665
std::vector<User*> Users::moves(const std::string& container) const {
77✔
666
    if (this->moves_.find(container) == this->moves_.end()) {
77✔
667
        return {};
76✔
668
    } else {
669
        return this->moves_.at(container);
1✔
670
    }
671
};
77✔
672

673
/****** Domination Analysis ******/
674

675
const std::unordered_map<User*, User*>& Users::dominator_tree() {
×
676
    if (this->dom_tree_.empty()) {
×
677
        this->init_dom_tree();
×
678
    }
×
679
    return this->dom_tree_;
×
680
};
681

682
bool Users::dominates(User& user1, User& user) {
224✔
683
    if (this->dom_tree_.empty()) {
224✔
684
        this->init_dom_tree();
69✔
685
    }
69✔
686
    auto dominator = this->dom_tree_.at(&user);
224✔
687
    while (dominator != nullptr) {
2,037✔
688
        if (dominator == &user1) {
2,037✔
689
            return true;
224✔
690
        }
691
        dominator = this->dom_tree_.at(dominator);
1,813✔
692
    }
693
    return false;
×
694
};
224✔
695

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

703
bool Users::post_dominates(User& user1, User& user) {
98✔
704
    if (this->pdom_tree_.empty()) {
98✔
705
        this->init_dom_tree();
×
706
    }
×
707
    auto dominator = this->pdom_tree_.at(&user);
98✔
708
    while (dominator != nullptr) {
958✔
709
        if (dominator == &user1) {
958✔
710
            return true;
98✔
711
        }
712
        dominator = this->pdom_tree_.at(dominator);
860✔
713
    }
714
    return false;
×
715
};
98✔
716

717
const std::unordered_set<User*> Users::all_uses_between(User& user1, User& user) {
106✔
718
    if (!this->dominates(user1, user)) {
106✔
NEW
719
        throw InvalidSDFGException("Users Analysis: User1 does not dominate user");
×
720
    }
721

722
    std::unordered_set<User*> uses;
106✔
723
    std::unordered_set<User*> visited;
106✔
724
    std::list<User*> queue = {&user};
106✔
725
    while (!queue.empty()) {
2,306✔
726
        auto current = queue.front();
2,200✔
727
        queue.pop_front();
2,200✔
728

729
        // Stop conditions
730
        if (current == &user1) {
2,200✔
731
            continue;
106✔
732
        }
733

734
        if (visited.find(current) != visited.end()) {
2,094✔
735
            continue;
208✔
736
        }
737
        visited.insert(current);
1,886✔
738

739
        if (current != &user1 && current != &user) {
1,886✔
740
            uses.insert(current);
1,780✔
741
        }
1,780✔
742

743
        // Extend search
744
        // Backward search to utilize domination user1 over user
745
        auto [eb, ee] = boost::in_edges(current->vertex_, this->graph_);
1,886✔
746
        auto edges = std::ranges::subrange(eb, ee);
3,772✔
747
        for (auto edge : edges) {
3,980✔
748
            auto v = boost::source(edge, this->graph_);
2,094✔
749
            queue.push_back(this->users_.at(v).get());
2,094✔
750
        }
751
    }
752

753
    return uses;
106✔
754
};
106✔
755

756
const std::unordered_set<User*> Users::all_uses_after(User& user1) {
×
757
    std::unordered_set<User*> uses;
×
758
    std::unordered_set<User*> visited;
×
759
    std::list<User*> queue = {&user1};
×
760
    while (!queue.empty()) {
×
761
        auto current = queue.front();
×
762
        queue.pop_front();
×
763
        if (visited.find(current) != visited.end()) {
×
764
            continue;
×
765
        }
766
        visited.insert(current);
×
767

768
        if (current != &user1) {
×
769
            uses.insert(current);
×
770
        }
×
771

772
        // Extend search
773
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
774
        auto edges = std::ranges::subrange(eb, ee);
×
775
        for (auto edge : edges) {
×
776
            auto v = boost::target(edge, this->graph_);
×
777
            queue.push_back(this->users_.at(v).get());
×
778
        }
779
    }
780

781
    return uses;
×
782
};
×
783

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

787
    std::unordered_set<User*> sources;
2✔
788
    std::unordered_set<User*> visited;
2✔
789
    std::list<User*> queue = {source};
2✔
790
    while (!queue.empty()) {
9✔
791
        auto current = queue.front();
7✔
792
        queue.pop_front();
7✔
793
        if (visited.find(current) != visited.end()) {
7✔
794
            continue;
×
795
        }
796
        visited.insert(current);
7✔
797

798
        if (current->container() == container) {
7✔
799
            sources.insert(current);
2✔
800
            continue;
2✔
801
        }
802

803
        // Extend search
804
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
5✔
805
        auto edges = std::ranges::subrange(eb, ee);
10✔
806
        for (auto edge : edges) {
10✔
807
            auto v = boost::target(edge, this->graph_);
5✔
808
            queue.push_back(this->users_.at(v).get());
5✔
809
        }
810
    }
811

812
    return sources;
2✔
813
};
2✔
814

815
/****** Happens-Before Analysis ******/
816

817
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::read_subsets() {
×
818
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
×
819
    for (auto& read : this->users_) {
×
820
        if (read.second->use() != Use::READ) {
×
821
            continue;
×
822
        }
823

824
        auto& data = read.second->container();
×
825
        if (readset.find(data) == readset.end()) {
×
826
            readset[data] = std::vector<data_flow::Subset>();
×
827
        }
×
828
        auto& subsets = read.second->subsets();
×
829
        for (auto& subset : subsets) {
×
830
            readset[data].push_back(subset);
×
831
        }
832
    }
×
833
    return readset;
×
834
};
×
835

836
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::write_subsets() {
×
837
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
838
    for (auto& write : this->users_) {
×
839
        if (write.second->use() != Use::WRITE) {
×
840
            continue;
×
841
        }
842

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

855
std::unordered_set<std::string> Users::locals(StructuredSDFG& sdfg,
75✔
856
                                              structured_control_flow::ControlFlowNode& node) {
857
    // Collect all node elements
858
    Users local_users(sdfg, node);
75✔
859
    analysis::AnalysisManager analysis_manager(sdfg_);
75✔
860
    local_users.run(analysis_manager);
75✔
861
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
75✔
862
    for (auto& entry : local_users.users_) {
1,791✔
863
        if (entry.second->use() == Use::NOP) {
1,716✔
864
            continue;
642✔
865
        }
866
        if (!sdfg.is_transient(entry.second->container())) {
1,074✔
867
            continue;
321✔
868
        }
869

870
        if (elements.find(entry.second->container()) == elements.end()) {
753✔
871
            elements[entry.second->container()] = {};
212✔
872
        }
212✔
873
        elements[entry.second->container()].insert(entry.second->element());
753✔
874
    }
875

876
    // Determine locals
877
    for (auto& entry : this->users_) {
3,213✔
878
        if (entry.second->use() == Use::NOP) {
3,138✔
879
            continue;
1,256✔
880
        }
881

882
        auto& container = entry.second->container();
1,882✔
883
        auto element = entry.second->element();
1,882✔
884
        if (elements.find(container) == elements.end()) {
1,882✔
885
            continue;
1,271✔
886
        }
887
        // used outside of node
888
        if (elements[container].find(element) == elements[container].end()) {
611✔
889
            elements.erase(container);
114✔
890
        }
114✔
891
    }
892

893
    std::unordered_set<std::string> locals;
75✔
894
    for (auto& entry : elements) {
173✔
895
        locals.insert(entry.first);
98✔
896
    }
897
    return locals;
75✔
898
};
75✔
899

900
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
92✔
901
    auto& entry = users.entries_.at(&node);
92✔
902
    auto& exit = users.exits_.at(&node);
92✔
903
    if (!users.dominates(*entry, *exit)) {
92✔
NEW
904
        throw InvalidSDFGException("Users Analysis: Entry does not dominate exit");
×
905
    }
906
    if (!users.post_dominates(*exit, *entry)) {
92✔
NEW
907
        throw InvalidSDFGException("Users Analysis: Exit does not post-dominate entry");
×
908
    }
909

910
    this->entry_ = entry;
92✔
911
    this->exit_ = exit;
92✔
912
    this->sub_users_ = users.all_uses_between(*entry, *exit);
92✔
913
};
92✔
914

915
std::vector<User*> UsersView::uses() const {
×
916
    std::vector<User*> us;
×
917
    for (auto& user : this->sub_users_) {
×
918
        if (user->use() == Use::NOP) {
×
919
            continue;
×
920
        }
921
        us.push_back(user);
×
922
    }
923

924
    return us;
×
925
};
×
926

927
std::vector<User*> UsersView::uses(const std::string& container) const {
10✔
928
    std::vector<User*> us;
10✔
929
    for (auto& user : this->sub_users_) {
97✔
930
        if (user->container() != container) {
87✔
931
            continue;
70✔
932
        }
933
        if (user->use() == Use::NOP) {
17✔
934
            continue;
×
935
        }
936
        us.push_back(user);
17✔
937
    }
938

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

942
std::vector<User*> UsersView::writes() const {
77✔
943
    std::vector<User*> us;
77✔
944
    for (auto& user : this->sub_users_) {
1,657✔
945
        if (user->use() != Use::WRITE) {
1,580✔
946
            continue;
1,335✔
947
        }
948
        us.push_back(user);
245✔
949
    }
950

951
    return us;
77✔
952
};
77✔
953

954
std::vector<User*> UsersView::writes(const std::string& container) const {
109✔
955
    std::vector<User*> us;
109✔
956
    for (auto& user : this->sub_users_) {
3,615✔
957
        if (user->container() != container) {
3,506✔
958
            continue;
3,305✔
959
        }
960
        if (user->use() != Use::WRITE) {
201✔
961
            continue;
89✔
962
        }
963
        us.push_back(user);
112✔
964
    }
965

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

969
std::vector<User*> UsersView::reads() const {
74✔
970
    std::vector<User*> us;
74✔
971
    for (auto& user : this->sub_users_) {
1,633✔
972
        if (user->use() != Use::READ) {
1,559✔
973
            continue;
729✔
974
        }
975
        us.push_back(user);
830✔
976
    }
977

978
    return us;
74✔
979
};
74✔
980

981
std::vector<User*> UsersView::reads(const std::string& container) const {
99✔
982
    std::vector<User*> us;
99✔
983
    for (auto& user : this->sub_users_) {
3,442✔
984
        if (user->container() != container) {
3,343✔
985
            continue;
3,164✔
986
        }
987
        if (user->use() != Use::READ) {
179✔
988
            continue;
91✔
989
        }
990
        us.push_back(user);
88✔
991
    }
992

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

996
std::vector<User*> UsersView::views() const {
80✔
997
    std::vector<User*> us;
80✔
998
    for (auto& user : this->sub_users_) {
1,683✔
999
        if (user->use() != Use::VIEW) {
1,603✔
1000
            continue;
1,603✔
1001
        }
1002
        us.push_back(user);
×
1003
    }
1004

1005
    return us;
80✔
1006
};
80✔
1007

1008
std::vector<User*> UsersView::views(const std::string& container) const {
1✔
1009
    std::vector<User*> us;
1✔
1010
    for (auto& user : this->sub_users_) {
28✔
1011
        if (user->container() != container) {
27✔
1012
            continue;
26✔
1013
        }
1014
        if (user->use() != Use::VIEW) {
1✔
1015
            continue;
1✔
1016
        }
1017
        us.push_back(user);
×
1018
    }
1019

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

1023
std::vector<User*> UsersView::moves() const {
80✔
1024
    std::vector<User*> us;
80✔
1025
    for (auto& user : this->sub_users_) {
1,683✔
1026
        if (user->use() != Use::MOVE) {
1,603✔
1027
            continue;
1,603✔
1028
        }
1029
        us.push_back(user);
×
1030
    }
1031

1032
    return us;
80✔
1033
};
80✔
1034

1035
std::vector<User*> UsersView::moves(const std::string& container) const {
5✔
1036
    std::vector<User*> us;
5✔
1037
    for (auto& user : this->sub_users_) {
140✔
1038
        if (user->container() != container) {
135✔
1039
            continue;
122✔
1040
        }
1041
        if (user->use() != Use::MOVE) {
13✔
1042
            continue;
13✔
1043
        }
1044
        us.push_back(user);
×
1045
    }
1046

1047
    return us;
5✔
1048
};
5✔
1049

1050
std::unordered_map<User*, User*> UsersView::dominator_tree() {
×
1051
    if (!this->sub_dom_tree_.empty()) {
×
1052
        return this->sub_dom_tree_;
×
1053
    }
1054

1055
    auto dom_tree = this->users_.dominator_tree();
×
1056
    std::unordered_map<User*, User*> sub_dom_tree;
×
1057
    for (auto& entry : this->sub_users_) {
×
1058
        sub_dom_tree[entry] = dom_tree[entry];
×
1059
    }
1060
    sub_dom_tree[this->entry_] = nullptr;
×
1061
    return sub_dom_tree;
×
1062
};
×
1063

1064
bool UsersView::dominates(User& user1, User& user) {
×
1065
    auto dom_tree = this->dominator_tree();
×
1066
    auto dominator = dom_tree[&user];
×
1067
    while (dominator != nullptr) {
×
1068
        if (dominator == &user1) {
×
1069
            return true;
×
1070
        }
1071
        dominator = dom_tree[dominator];
×
1072
    }
1073
    return false;
×
1074
};
×
1075

1076
std::unordered_map<User*, User*> UsersView::post_dominator_tree() {
×
1077
    if (!this->sub_pdom_tree_.empty()) {
×
1078
        return this->sub_pdom_tree_;
×
1079
    }
1080

1081
    auto pdom_tree = this->users_.post_dominator_tree();
×
1082
    std::unordered_map<User*, User*> sub_pdom_tree;
×
1083
    for (auto& entry : this->sub_users_) {
×
1084
        sub_pdom_tree[entry] = pdom_tree[entry];
×
1085
    }
1086
    sub_pdom_tree[this->exit_] = nullptr;
×
1087
    return sub_pdom_tree;
×
1088
};
×
1089

1090
bool UsersView::post_dominates(User& user1, User& user) {
×
1091
    auto pdom_tree = this->post_dominator_tree();
×
1092
    auto dominator = pdom_tree[&user];
×
1093
    while (dominator != nullptr) {
×
1094
        if (dominator == &user1) {
×
1095
            return true;
×
1096
        }
1097
        dominator = pdom_tree[dominator];
×
1098
    }
1099
    return false;
×
1100
};
×
1101

1102
std::unordered_set<User*> UsersView::all_uses_between(User& user1, User& user) {
×
1103
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1104
    assert(this->sub_users_.find(&user) != this->sub_users_.end());
×
NEW
1105
    if (!this->dominates(user1, user)) {
×
NEW
1106
        throw InvalidSDFGException("Users Analysis: User1 does not dominate user");
×
1107
    }
UNCOV
1108
    bool post_dominates = this->post_dominates(user, user1);
×
1109

1110
    std::unordered_set<User*> uses;
×
1111
    std::unordered_set<User*> visited;
×
1112
    std::list<User*> queue = {&user1};
×
1113
    while (!queue.empty()) {
×
1114
        auto current = queue.front();
×
1115
        queue.pop_front();
×
1116
        if (visited.find(current) != visited.end()) {
×
1117
            continue;
×
1118
        }
1119
        visited.insert(current);
×
1120

1121
        if (current != &user1 && current != &user) {
×
1122
            uses.insert(current);
×
1123
        }
×
1124

1125
        // Stop conditions
1126
        if (current == exit_) {
×
1127
            continue;
×
1128
        }
1129

1130
        if (current == &user) {
×
1131
            continue;
×
1132
        } else if (!post_dominates) {
×
1133
            if (this->post_dominates(*current, user)) {
×
1134
                continue;
×
1135
            }
1136
        }
×
1137

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

1147
    return uses;
×
1148
};
×
1149

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

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

1164
        if (current != &user1) {
×
1165
            uses.insert(current);
×
1166
        }
×
1167

1168
        if (current == exit_) {
×
1169
            continue;
×
1170
        }
1171

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

1181
    return uses;
×
1182
};
×
1183

1184
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::read_subsets() {
6✔
1185
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
6✔
1186
    for (auto& read : this->sub_users_) {
50✔
1187
        if (read->use() != Use::READ) {
44✔
1188
            continue;
24✔
1189
        }
1190

1191
        auto& data = read->container();
20✔
1192
        if (readset.find(data) == readset.end()) {
20✔
1193
            readset[data] = std::vector<data_flow::Subset>();
14✔
1194
        }
14✔
1195
        auto& subsets = read->subsets();
20✔
1196
        for (auto& subset : subsets) {
40✔
1197
            readset[data].push_back(subset);
20✔
1198
        }
1199
    }
20✔
1200
    return readset;
6✔
1201
};
6✔
1202

1203
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::write_subsets() {
6✔
1204
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
6✔
1205
    for (auto& write : this->sub_users_) {
50✔
1206
        if (write->use() != Use::WRITE) {
44✔
1207
            continue;
36✔
1208
        }
1209

1210
        auto& data = write->container();
8✔
1211
        if (writeset.find(data) == writeset.end()) {
8✔
1212
            writeset[data] = std::vector<data_flow::Subset>();
8✔
1213
        }
8✔
1214
        auto& subsets = write->subsets();
8✔
1215
        for (auto& subset : subsets) {
16✔
1216
            writeset[data].push_back(subset);
8✔
1217
        }
1218
    }
8✔
1219
    return writeset;
6✔
1220
};
6✔
1221

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

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

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

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

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

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

1283
void Users::add_user(std::unique_ptr<User> user) {
2,304✔
1284
    auto vertex = user->vertex_;
2,304✔
1285
    this->users_.insert({vertex, std::move(user)});
2,304✔
1286

1287
    auto user_ptr = this->users_.at(vertex).get();
2,304✔
1288
    auto* target_structure = &users_by_sdfg_;
2,304✔
1289
    if (auto for_user = dynamic_cast<ForUser*>(user_ptr)) {
2,304✔
1290
        auto for_loop = dynamic_cast<structured_control_flow::For*>(user_ptr->element());
863✔
1291
        if (for_loop == nullptr) {
863✔
1292
            throw std::invalid_argument("Invalid user type");
×
1293
        }
1294
        if (for_user->is_init()) {
863✔
1295
            target_structure = &users_by_sdfg_loop_init_;
210✔
1296
        } else if (for_user->is_condition()) {
863✔
1297
            target_structure = &users_by_sdfg_loop_condition_;
347✔
1298
        } else if (for_user->is_update()) {
653✔
1299
            target_structure = &users_by_sdfg_loop_update_;
306✔
1300
        } else {
306✔
1301
            throw std::invalid_argument("Invalid user type");
×
1302
        }
1303
    }
863✔
1304

1305
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
2,304✔
1306
        target_structure->insert({user_ptr->container(), {}});
1,244✔
1307
    }
1,244✔
1308
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
4,608✔
1309
        (*target_structure)[user_ptr->container()].end()) {
2,304✔
1310
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
2,142✔
1311
    }
2,142✔
1312
    target_structure->at(user_ptr->container())
2,304✔
1313
        .at(user_ptr->element())
2,304✔
1314
        .insert({user_ptr->use(), user_ptr});
2,304✔
1315
}
2,304✔
1316

1317
}  // namespace analysis
1318
}  // 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