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

daisytuner / sdfglib / 15262928007

26 May 2025 10:36PM UTC coverage: 58.284% (-2.0%) from 60.304%
15262928007

push

github

web-flow
Merge pull request #36 from daisytuner/sdfg-validation

Introduces new definition of memlets plus sanity checks

104 of 266 new or added lines in 6 files covered. (39.1%)

241 existing lines in 15 files now uncovered.

7908 of 13568 relevant lines covered (58.28%)

96.1 hits per line

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

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

25
      };
2,704✔
26

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

31
      };
1,270✔
32

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

35
};
7,127✔
36

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

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

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

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

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

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

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

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

78
      };
821✔
79

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

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

84
bool ForUser::is_update() const { return this->is_update_; };
295✔
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) {
319✔
114
    graph::Vertex first = boost::graph_traits<graph::Graph>::null_vertex();
319✔
115
    graph::Vertex last = boost::graph_traits<graph::Graph>::null_vertex();
319✔
116
    for (auto node : dataflow.topological_sort()) {
1,103✔
117
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
784✔
118
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
528✔
119
                if (dataflow.in_degree(*node) > 0) {
528✔
120
                    Use use = Use::WRITE;
253✔
121
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
503✔
122
                        if (iedge.src_conn() == "refs" || iedge.dst_conn() == "refs") {
253✔
123
                            use = Use::MOVE;
3✔
124
                            break;
3✔
125
                        }
126
                    }
127

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

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

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

152
                    if (last != boost::graph_traits<graph::Graph>::null_vertex()) {
282✔
153
                        boost::add_edge(last, v, this->graph_);
65✔
154
                    } else {
65✔
155
                        first = v;
217✔
156
                    }
157
                    last = v;
282✔
158
                }
282✔
159
            }
528✔
160
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
784✔
161
            if (tasklet->is_conditional()) {
250✔
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
        }
250✔
177

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

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

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

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

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

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

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

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

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

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

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

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

285
        return {s, t};
383✔
286
    } else if (auto if_else_stmt = dynamic_cast<structured_control_flow::IfElse*>(&node)) {
191✔
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)) {
191✔
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)) {
163✔
358
        // NOP
359
        auto s = boost::add_vertex(this->graph_);
145✔
360
        this->users_.insert({s, std::make_unique<User>(s, "", for_stmt, Use::NOP)});
145✔
361
        auto last = s;
145✔
362
        this->entries_.insert({for_stmt, this->users_.at(s).get()});
145✔
363

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

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

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

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

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

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

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

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

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

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

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

428
        return {s, t};
145✔
429
    } else if (auto cont_stmt = dynamic_cast<structured_control_flow::Continue*>(&node)) {
18✔
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)) {
13✔
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)) {
8✔
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)) {
8✔
450
        // NOP
451
        auto s = boost::add_vertex(this->graph_);
8✔
452
        this->users_.insert({s, std::make_unique<User>(s, "", kern_stmt, Use::NOP)});
8✔
453
        this->entries_.insert({kern_stmt, this->users_.at(s).get()});
8✔
454

455
        auto subgraph = this->traverse(kern_stmt->root());
8✔
456
        boost::add_edge(s, subgraph.first, this->graph_);
8✔
457
        if (subgraph.second == boost::graph_traits<graph::Graph>::null_vertex()) {
8✔
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_);
8✔
463
        this->users_.insert({t, std::make_unique<User>(t, "", kern_stmt, Use::NOP)});
8✔
464
        boost::add_edge(subgraph.second, t, this->graph_);
8✔
465
        this->exits_.insert({kern_stmt, this->users_.at(t).get()});
8✔
466

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

470
    throw std::invalid_argument("Invalid control flow node type");
×
471
};
893✔
472

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

476
      };
117✔
477

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

481
      };
68✔
482

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

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

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

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

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

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

542
    // Collect sub structures
543
    for (auto& entry : this->users_) {
4,159✔
544
        auto container = entry.second->container();
3,974✔
545
        switch (entry.second->use()) {
3,974✔
546
            case Use::READ: {
547
                if (this->reads_.find(container) == this->reads_.end()) {
1,588✔
548
                    this->reads_.insert({container, {}});
675✔
549
                }
675✔
550
                this->reads_[container].push_back(entry.second.get());
1,588✔
551
                break;
1,588✔
552
            }
553
            case Use::WRITE: {
554
                if (this->writes_.find(container) == this->writes_.end()) {
604✔
555
                    this->writes_.insert({container, {}});
405✔
556
                }
405✔
557
                this->writes_[container].push_back(entry.second.get());
604✔
558
                break;
604✔
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,776✔
576
        }
577
    }
3,974✔
578
};
185✔
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) {
93✔
732
    std::unordered_set<User*> uses;
93✔
733
    std::unordered_set<User*> visited;
93✔
734
    std::list<User*> queue = {&user};
93✔
735
    while (!queue.empty()) {
2,159✔
736
        auto current = queue.front();
2,066✔
737
        queue.pop_front();
2,066✔
738

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

744
        if (visited.find(current) != visited.end()) {
1,973✔
745
            continue;
205✔
746
        }
747
        visited.insert(current);
1,768✔
748

749
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
1,768✔
750
            uses.insert(current);
1,142✔
751
        }
1,142✔
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,768✔
756
        auto edges = std::ranges::subrange(eb, ee);
3,536✔
757
        for (auto edge : edges) {
3,741✔
758
            auto v = boost::source(edge, this->graph_);
1,973✔
759
            queue.push_back(this->users_.at(v).get());
1,973✔
760
        }
761
    }
762

763
    return uses;
93✔
764
};
93✔
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

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,
68✔
866
                                              structured_control_flow::ControlFlowNode& node) {
867
    // Collect all node elements
868
    Users local_users(sdfg, node);
68✔
869
    analysis::AnalysisManager analysis_manager(sdfg_);
68✔
870
    local_users.run(analysis_manager);
68✔
871
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
68✔
872
    for (auto& entry : local_users.users_) {
1,709✔
873
        if (entry.second->use() == Use::NOP) {
1,641✔
874
            continue;
606✔
875
        }
876
        if (!sdfg.is_transient(entry.second->container())) {
1,035✔
877
            continue;
303✔
878
        }
879

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

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

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

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

910
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
79✔
911
    auto& entry = users.entries_.at(&node);
79✔
912
    auto& exit = users.exits_.at(&node);
79✔
913
    this->entry_ = entry;
79✔
914
    this->exit_ = exit;
79✔
915
    this->sub_users_ = users.all_uses_between(*entry, *exit);
79✔
916
};
79✔
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 {
70✔
946
    std::vector<User*> us;
70✔
947
    for (auto& user : this->sub_users_) {
1,115✔
948
        if (user->use() != Use::WRITE) {
1,045✔
949
            continue;
811✔
950
        }
951
        us.push_back(user);
234✔
952
    }
953

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

957
std::vector<User*> UsersView::writes(const std::string& container) const {
97✔
958
    std::vector<User*> us;
97✔
959
    for (auto& user : this->sub_users_) {
2,542✔
960
        if (user->container() != container) {
2,445✔
961
            continue;
2,265✔
962
        }
963
        if (user->use() != Use::WRITE) {
180✔
964
            continue;
80✔
965
        }
966
        us.push_back(user);
100✔
967
    }
968

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

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

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

984
std::vector<User*> UsersView::reads(const std::string& container) const {
90✔
985
    std::vector<User*> us;
90✔
986
    for (auto& user : this->sub_users_) {
2,465✔
987
        if (user->container() != container) {
2,375✔
988
            continue;
2,212✔
989
        }
990
        if (user->use() != Use::READ) {
163✔
991
            continue;
82✔
992
        }
993
        us.push_back(user);
81✔
994
    }
995

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

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

1008
    return us;
67✔
1009
};
67✔
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 {
67✔
1027
    std::vector<User*> us;
67✔
1028
    for (auto& user : this->sub_users_) {
1,101✔
1029
        if (user->use() != Use::MOVE) {
1,034✔
1030
            continue;
1,034✔
1031
        }
1032
        us.push_back(user);
×
1033
    }
1034

1035
    return us;
67✔
1036
};
67✔
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

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

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

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

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

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

UNCOV
1205
        auto& data = write->container();
×
UNCOV
1206
        if (writeset.find(data) == writeset.end()) {
×
UNCOV
1207
            writeset[data] = std::vector<data_flow::Subset>();
×
UNCOV
1208
        }
×
UNCOV
1209
        auto& subsets = write->subsets();
×
UNCOV
1210
        for (auto& subset : subsets) {
×
UNCOV
1211
            writeset[data].push_back(subset);
×
1212
        }
UNCOV
1213
    }
×
UNCOV
1214
    return writeset;
×
UNCOV
1215
};
×
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,
304✔
1263
                      bool is_condition, bool is_update) {
1264
    if (auto for_loop = dynamic_cast<structured_control_flow::For*>(element)) {
304✔
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);
266✔
1275
    return tmp;
266✔
1276
}
304✔
1277

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

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

1300
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
2,198✔
1301
        target_structure->insert({user_ptr->container(), {}});
1,176✔
1302
    }
1,176✔
1303
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
4,396✔
1304
        (*target_structure)[user_ptr->container()].end()) {
2,198✔
1305
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
2,044✔
1306
    }
2,044✔
1307
    target_structure->at(user_ptr->container())
2,198✔
1308
        .at(user_ptr->element())
2,198✔
1309
        .insert({user_ptr->use(), user_ptr});
2,198✔
1310
}
2,198✔
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