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

daisytuner / sdfglib / 15241626882

25 May 2025 08:19PM UTC coverage: 60.336% (-0.006%) from 60.342%
15241626882

push

github

web-flow
Merge pull request #34 from daisytuner/users-analysis

Releaxes domination and post-domination requirements of users analysis

7 of 19 new or added lines in 1 file covered. (36.84%)

2 existing lines in 1 file now uncovered.

8050 of 13342 relevant lines covered (60.34%)

97.38 hits per line

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

70.66
/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,060✔
38

39
std::string& User::container() { return this->container_; };
29,680✔
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 {
411✔
46
    if (this->container_ == "") {
411✔
47
        return {};
×
48
    }
49

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

67
    // Use of symbol
68
    return {{sdfg::symbolic::integer(0)}};
11✔
69
};
411✔
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() {
19✔
87
    this->dom_tree_.clear();
19✔
88
    this->pdom_tree_.clear();
19✔
89

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

101
    // Compute post-dominator-tree
102
    auto pdom_tree = graph::post_dominator_tree(this->graph_, this->sink_->vertex_);
19✔
103
    for (auto& entry : pdom_tree) {
231✔
104
        User* first = this->users_.at(entry.first).get();
212✔
105
        User* second = nullptr;
212✔
106
        if (entry.second != boost::graph_traits<graph::Graph>::null_vertex()) {
212✔
107
            second = this->users_.at(entry.second).get();
193✔
108
        }
193✔
109
        this->pdom_tree_.insert({first, second});
212✔
110
    }
111
};
19✔
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✔
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✔
515
        throw InvalidSDFGException("Users Analysis: No source node");
×
516
    }
517

518
    std::list<User*> sinks;
199✔
519
    for (auto& entry : this->users_) {
4,379✔
520
        if (boost::out_degree(entry.first, this->graph_) == 0) {
4,180✔
521
            sinks.push_back(entry.second.get());
199✔
522
        }
199✔
523
    }
524
    if (sinks.size() == 0) {
199✔
NEW
525
        throw InvalidSDFGException("Users Analysis: No sink node");
×
526
    }
527
    if (sinks.size() > 1) {
199✔
528
        // add artificial sink
NEW
529
        auto v = boost::add_vertex(this->graph_);
×
NEW
530
        auto sink = std::make_unique<User>(v, "", nullptr, Use::NOP);
×
NEW
531
        this->users_.insert({v, std::move(sink)});
×
NEW
532
        for (auto sink : sinks) {
×
NEW
533
            boost::add_edge(sink->vertex_, v, this->graph_);
×
534
        }
NEW
535
        sinks.clear();
×
536

NEW
537
        this->sink_ = this->users_.at(v).get();
×
NEW
538
    } else {
×
539
        this->sink_ = sinks.front();
199✔
540
    }
541

542
    // Collect sub structures
543
    for (auto& entry : this->users_) {
4,379✔
544
        auto container = entry.second->container();
4,180✔
545
        switch (entry.second->use()) {
4,180✔
546
            case Use::READ: {
547
                if (this->reads_.find(container) == this->reads_.end()) {
1,660✔
548
                    this->reads_.insert({container, {}});
716✔
549
                }
716✔
550
                this->reads_[container].push_back(entry.second.get());
1,660✔
551
                break;
1,660✔
552
            }
553
            case Use::WRITE: {
554
                if (this->writes_.find(container) == this->writes_.end()) {
638✔
555
                    this->writes_.insert({container, {}});
431✔
556
                }
431✔
557
                this->writes_[container].push_back(entry.second.get());
638✔
558
                break;
638✔
559
            }
560
            case Use::VIEW: {
561
                if (this->views_.find(container) == this->views_.end()) {
3✔
562
                    this->views_.insert({container, {}});
3✔
563
                }
3✔
564
                this->views_[container].push_back(entry.second.get());
3✔
565
                break;
3✔
566
            }
567
            case Use::MOVE: {
568
                if (this->moves_.find(container) == this->moves_.end()) {
3✔
569
                    this->moves_.insert({container, {}});
3✔
570
                }
3✔
571
                this->moves_[container].push_back(entry.second.get());
3✔
572
                break;
3✔
573
            }
574
            default:
575
                break;
1,876✔
576
        }
577
    }
4,180✔
578
};
199✔
579

580
std::vector<User*> Users::uses() const {
×
581
    std::vector<User*> us;
×
582
    for (auto& entry : this->users_) {
×
583
        if (entry.second->use() == Use::NOP) {
×
584
            continue;
×
585
        }
586
        us.push_back(entry.second.get());
×
587
    }
588

589
    return us;
×
590
};
×
591

592
std::vector<User*> Users::uses(const std::string& container) const {
1✔
593
    std::vector<User*> us;
1✔
594
    for (auto& entry : this->users_) {
10✔
595
        if (entry.second->container() != container) {
9✔
596
            continue;
7✔
597
        }
598
        if (entry.second->use() == Use::NOP) {
2✔
599
            continue;
×
600
        }
601
        us.push_back(entry.second.get());
2✔
602
    }
603

604
    return us;
1✔
605
};
1✔
606

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

616
    return us;
×
617
};
×
618

619
std::vector<User*> Users::writes(const std::string& container) const {
66✔
620
    if (this->writes_.find(container) == this->writes_.end()) {
66✔
621
        return {};
25✔
622
    } else {
623
        return this->writes_.at(container);
41✔
624
    }
625
};
66✔
626

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

636
    return us;
×
637
};
×
638

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

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

656
    return us;
×
657
};
×
658

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

667
std::vector<User*> Users::moves() const {
×
668
    std::vector<User*> us;
×
669
    for (auto& entry : this->users_) {
×
670
        if (entry.second->use() != Use::MOVE) {
×
671
            continue;
×
672
        }
673
        us.push_back(entry.second.get());
×
674
    }
675

676
    return us;
×
677
};
×
678

679
std::vector<User*> Users::moves(const std::string& container) const {
77✔
680
    if (this->moves_.find(container) == this->moves_.end()) {
77✔
681
        return {};
76✔
682
    } else {
683
        return this->moves_.at(container);
1✔
684
    }
685
};
77✔
686

687
/****** Domination Analysis ******/
688

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

696
bool Users::dominates(User& user1, User& user) {
26✔
697
    if (this->dom_tree_.empty()) {
26✔
698
        this->init_dom_tree();
19✔
699
    }
19✔
700
    auto dominator = this->dom_tree_.at(&user);
26✔
701
    while (dominator != nullptr) {
88✔
702
        if (dominator == &user1) {
88✔
703
            return true;
26✔
704
        }
705
        dominator = this->dom_tree_.at(dominator);
62✔
706
    }
707
    return false;
×
708
};
26✔
709

710
const std::unordered_map<User*, User*>& Users::post_dominator_tree() {
×
711
    if (this->pdom_tree_.empty()) {
×
712
        this->init_dom_tree();
×
713
    }
×
714
    return this->pdom_tree_;
×
715
};
716

717
bool Users::post_dominates(User& user1, User& user) {
6✔
718
    if (this->pdom_tree_.empty()) {
6✔
719
        this->init_dom_tree();
×
720
    }
×
721
    auto dominator = this->pdom_tree_.at(&user);
6✔
722
    while (dominator != nullptr) {
12✔
723
        if (dominator == &user1) {
12✔
724
            return true;
6✔
725
        }
726
        dominator = this->pdom_tree_.at(dominator);
6✔
727
    }
728
    return false;
×
729
};
6✔
730

731
const std::unordered_set<User*> Users::all_uses_between(User& user1, User& user) {
106✔
732
    std::unordered_set<User*> uses;
106✔
733
    std::unordered_set<User*> visited;
106✔
734
    std::list<User*> queue = {&user};
106✔
735
    while (!queue.empty()) {
2,306✔
736
        auto current = queue.front();
2,200✔
737
        queue.pop_front();
2,200✔
738

739
        // Stop conditions
740
        if (current == &user1) {
2,200✔
741
            continue;
106✔
742
        }
743

744
        if (visited.find(current) != visited.end()) {
2,094✔
745
            continue;
208✔
746
        }
747
        visited.insert(current);
1,886✔
748

749
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
1,886✔
750
            uses.insert(current);
1,209✔
751
        }
1,209✔
752

753
        // Extend search
754
        // Backward search to utilize domination user1 over user
755
        auto [eb, ee] = boost::in_edges(current->vertex_, this->graph_);
1,886✔
756
        auto edges = std::ranges::subrange(eb, ee);
3,772✔
757
        for (auto edge : edges) {
3,980✔
758
            auto v = boost::source(edge, this->graph_);
2,094✔
759
            queue.push_back(this->users_.at(v).get());
2,094✔
760
        }
761
    }
762

763
    return uses;
106✔
764
};
106✔
765

766
const std::unordered_set<User*> Users::all_uses_after(User& user1) {
×
767
    std::unordered_set<User*> uses;
×
768
    std::unordered_set<User*> visited;
×
769
    std::list<User*> queue = {&user1};
×
770
    while (!queue.empty()) {
×
771
        auto current = queue.front();
×
772
        queue.pop_front();
×
773
        if (visited.find(current) != visited.end()) {
×
774
            continue;
×
775
        }
776
        visited.insert(current);
×
777

NEW
778
        if (current != &user1 && current->use() != Use::NOP) {
×
779
            uses.insert(current);
×
780
        }
×
781

782
        // Extend search
783
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
784
        auto edges = std::ranges::subrange(eb, ee);
×
785
        for (auto edge : edges) {
×
786
            auto v = boost::target(edge, this->graph_);
×
787
            queue.push_back(this->users_.at(v).get());
×
788
        }
789
    }
790

791
    return uses;
×
792
};
×
793

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

797
    std::unordered_set<User*> sources;
2✔
798
    std::unordered_set<User*> visited;
2✔
799
    std::list<User*> queue = {source};
2✔
800
    while (!queue.empty()) {
9✔
801
        auto current = queue.front();
7✔
802
        queue.pop_front();
7✔
803
        if (visited.find(current) != visited.end()) {
7✔
804
            continue;
×
805
        }
806
        visited.insert(current);
7✔
807

808
        if (current->container() == container && current->use() != Use::NOP) {
7✔
809
            sources.insert(current);
2✔
810
            continue;
2✔
811
        }
812

813
        // Extend search
814
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
5✔
815
        auto edges = std::ranges::subrange(eb, ee);
10✔
816
        for (auto edge : edges) {
10✔
817
            auto v = boost::target(edge, this->graph_);
5✔
818
            queue.push_back(this->users_.at(v).get());
5✔
819
        }
820
    }
821

822
    return sources;
2✔
823
};
2✔
824

825
/****** Happens-Before Analysis ******/
826

827
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::read_subsets() {
×
828
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
×
829
    for (auto& read : this->users_) {
×
830
        if (read.second->use() != Use::READ) {
×
831
            continue;
×
832
        }
833

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

846
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::write_subsets() {
×
847
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
848
    for (auto& write : this->users_) {
×
849
        if (write.second->use() != Use::WRITE) {
×
850
            continue;
×
851
        }
852

853
        auto& data = write.second->container();
×
854
        if (writeset.find(data) == writeset.end()) {
×
855
            writeset[data] = std::vector<data_flow::Subset>();
×
856
        }
×
857
        auto& subsets = write.second->subsets();
×
858
        for (auto& subset : subsets) {
×
859
            writeset[data].push_back(subset);
×
860
        }
861
    }
×
862
    return writeset;
×
863
};
×
864

865
std::unordered_set<std::string> Users::locals(StructuredSDFG& sdfg,
75✔
866
                                              structured_control_flow::ControlFlowNode& node) {
867
    // Collect all node elements
868
    Users local_users(sdfg, node);
75✔
869
    analysis::AnalysisManager analysis_manager(sdfg_);
75✔
870
    local_users.run(analysis_manager);
75✔
871
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
75✔
872
    for (auto& entry : local_users.users_) {
1,791✔
873
        if (entry.second->use() == Use::NOP) {
1,716✔
874
            continue;
642✔
875
        }
876
        if (!sdfg.is_transient(entry.second->container())) {
1,074✔
877
            continue;
321✔
878
        }
879

880
        if (elements.find(entry.second->container()) == elements.end()) {
753✔
881
            elements[entry.second->container()] = {};
212✔
882
        }
212✔
883
        elements[entry.second->container()].insert(entry.second->element());
753✔
884
    }
885

886
    // Determine locals
887
    for (auto& entry : this->users_) {
3,213✔
888
        if (entry.second->use() == Use::NOP) {
3,138✔
889
            continue;
1,256✔
890
        }
891

892
        auto& container = entry.second->container();
1,882✔
893
        auto element = entry.second->element();
1,882✔
894
        if (elements.find(container) == elements.end()) {
1,882✔
895
            continue;
1,263✔
896
        }
897
        // used outside of node
898
        if (elements[container].find(element) == elements[container].end()) {
619✔
899
            elements.erase(container);
114✔
900
        }
114✔
901
    }
902

903
    std::unordered_set<std::string> locals;
75✔
904
    for (auto& entry : elements) {
173✔
905
        locals.insert(entry.first);
98✔
906
    }
907
    return locals;
75✔
908
};
75✔
909

910
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
92✔
911
    auto& entry = users.entries_.at(&node);
92✔
912
    auto& exit = users.exits_.at(&node);
92✔
913
    this->entry_ = entry;
92✔
914
    this->exit_ = exit;
92✔
915
    this->sub_users_ = users.all_uses_between(*entry, *exit);
92✔
916
};
92✔
917

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

927
    return us;
×
928
};
×
929

930
std::vector<User*> UsersView::uses(const std::string& container) const {
10✔
931
    std::vector<User*> us;
10✔
932
    for (auto& user : this->sub_users_) {
75✔
933
        if (user->container() != container) {
65✔
934
            continue;
48✔
935
        }
936
        if (user->use() == Use::NOP) {
17✔
937
            continue;
×
938
        }
939
        us.push_back(user);
17✔
940
    }
941

942
    return us;
10✔
943
};
10✔
944

945
std::vector<User*> UsersView::writes() const {
77✔
946
    std::vector<User*> us;
77✔
947
    for (auto& user : this->sub_users_) {
1,161✔
948
        if (user->use() != Use::WRITE) {
1,084✔
949
            continue;
839✔
950
        }
951
        us.push_back(user);
245✔
952
    }
953

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

957
std::vector<User*> UsersView::writes(const std::string& container) const {
109✔
958
    std::vector<User*> us;
109✔
959
    for (auto& user : this->sub_users_) {
2,611✔
960
        if (user->container() != container) {
2,502✔
961
            continue;
2,301✔
962
        }
963
        if (user->use() != Use::WRITE) {
201✔
964
            continue;
89✔
965
        }
966
        us.push_back(user);
112✔
967
    }
968

969
    return us;
109✔
970
};
109✔
971

972
std::vector<User*> UsersView::reads() const {
74✔
973
    std::vector<User*> us;
74✔
974
    for (auto& user : this->sub_users_) {
1,147✔
975
        if (user->use() != Use::READ) {
1,073✔
976
            continue;
243✔
977
        }
978
        us.push_back(user);
830✔
979
    }
980

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

984
std::vector<User*> UsersView::reads(const std::string& container) const {
99✔
985
    std::vector<User*> us;
99✔
986
    for (auto& user : this->sub_users_) {
2,518✔
987
        if (user->container() != container) {
2,419✔
988
            continue;
2,240✔
989
        }
990
        if (user->use() != Use::READ) {
179✔
991
            continue;
91✔
992
        }
993
        us.push_back(user);
88✔
994
    }
995

996
    return us;
99✔
997
};
99✔
998

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

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

1011
std::vector<User*> UsersView::views(const std::string& container) const {
1✔
1012
    std::vector<User*> us;
1✔
1013
    for (auto& user : this->sub_users_) {
24✔
1014
        if (user->container() != container) {
23✔
1015
            continue;
22✔
1016
        }
1017
        if (user->use() != Use::VIEW) {
1✔
1018
            continue;
1✔
1019
        }
1020
        us.push_back(user);
×
1021
    }
1022

1023
    return us;
1✔
1024
};
1✔
1025

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

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

1038
std::vector<User*> UsersView::moves(const std::string& container) const {
5✔
1039
    std::vector<User*> us;
5✔
1040
    for (auto& user : this->sub_users_) {
120✔
1041
        if (user->container() != container) {
115✔
1042
            continue;
102✔
1043
        }
1044
        if (user->use() != Use::MOVE) {
13✔
1045
            continue;
13✔
1046
        }
1047
        us.push_back(user);
×
1048
    }
1049

1050
    return us;
5✔
1051
};
5✔
1052

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

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

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

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

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

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

1105
std::unordered_set<User*> UsersView::all_uses_between(User& user1, User& user) {
×
1106
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1107
    assert(this->sub_users_.find(&user) != this->sub_users_.end());
×
1108

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

NEW
1120
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
×
1121
            uses.insert(current);
×
1122
        }
×
1123

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

1129
        if (current == &user) {
×
1130
            continue;
×
1131
        }
1132

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

1142
    return uses;
×
1143
};
×
1144

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

1148
    std::unordered_set<User*> uses;
×
1149
    std::unordered_set<User*> visited;
×
1150
    std::list<User*> queue = {&user1};
×
1151
    while (!queue.empty()) {
×
1152
        auto current = queue.front();
×
1153
        queue.pop_front();
×
1154
        if (visited.find(current) != visited.end()) {
×
1155
            continue;
×
1156
        }
1157
        visited.insert(current);
×
1158

NEW
1159
        if (current != &user1 && current->use() != Use::NOP) {
×
1160
            uses.insert(current);
×
1161
        }
×
1162

1163
        if (current == exit_) {
×
1164
            continue;
×
1165
        }
1166

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

1176
    return uses;
×
1177
};
×
1178

1179
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::read_subsets() {
6✔
1180
    std::unordered_map<std::string, std::vector<data_flow::Subset>> readset;
6✔
1181
    for (auto& read : this->sub_users_) {
34✔
1182
        if (read->use() != Use::READ) {
28✔
1183
            continue;
8✔
1184
        }
1185

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

1198
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::write_subsets() {
6✔
1199
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
6✔
1200
    for (auto& write : this->sub_users_) {
34✔
1201
        if (write->use() != Use::WRITE) {
28✔
1202
            continue;
20✔
1203
        }
1204

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

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

1232
        if (elements.find(entry.second->container()) == elements.end()) {
×
1233
            elements[entry.second->container()] = {};
×
1234
        }
×
1235
        elements[entry.second->container()].insert(entry.second->element());
×
1236
    }
1237

1238
    // Determine locals
1239
    for (auto& entry : this->sub_users_) {
×
1240
        if (entry->use() == Use::NOP) {
×
1241
            continue;
×
1242
        }
1243

1244
        auto& container = entry->container();
×
1245
        auto element = entry->element();
×
1246
        if (elements.find(container) == elements.end()) {
×
1247
            continue;
×
1248
        }
1249
        // used outside of node
1250
        if (elements[container].find(element) == elements[container].end()) {
×
1251
            elements.erase(container);
×
1252
        }
×
1253
    }
1254

1255
    std::unordered_set<std::string> locals;
×
1256
    for (auto& entry : elements) {
×
1257
        locals.insert(entry.first);
×
1258
    }
1259
    return locals;
×
1260
};
×
1261

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

1278
void Users::add_user(std::unique_ptr<User> user) {
2,304✔
1279
    auto vertex = user->vertex_;
2,304✔
1280
    this->users_.insert({vertex, std::move(user)});
2,304✔
1281

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

1300
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
2,304✔
1301
        target_structure->insert({user_ptr->container(), {}});
1,244✔
1302
    }
1,244✔
1303
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
4,608✔
1304
        (*target_structure)[user_ptr->container()].end()) {
2,304✔
1305
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
2,142✔
1306
    }
2,142✔
1307
    target_structure->at(user_ptr->container())
2,304✔
1308
        .at(user_ptr->element())
2,304✔
1309
        .insert({user_ptr->use(), user_ptr});
2,304✔
1310
}
2,304✔
1311

1312
}  // namespace analysis
1313
}  // 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