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

daisytuner / sdfglib / 15455990921

05 Jun 2025 01:03AM UTC coverage: 57.883% (-0.4%) from 58.236%
15455990921

push

github

web-flow
Merge pull request #56 from daisytuner/allocations

removes allocation handling

15 of 36 new or added lines in 4 files covered. (41.67%)

27 existing lines in 4 files now uncovered.

8018 of 13852 relevant lines covered (57.88%)

107.95 hits per line

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

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

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

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

20
namespace sdfg {
21
namespace analysis {
22

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

26
      };
2,791✔
27

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

32
      };
1,302✔
33

34
User::~User() {
7,339✔
35

36
};
7,339✔
37

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

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

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

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

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

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

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

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

79
      };
847✔
80

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

468
        return {s, t};
8✔
469
    } else if (auto map_stmt = dynamic_cast<structured_control_flow::Map*>(&node)) {
1✔
470
        // NOP
471
        auto s = boost::add_vertex(this->graph_);
1✔
472
        this->users_.insert({s, std::make_unique<User>(s, "", map_stmt, Use::NOP)});
1✔
473
        auto last = s;
1✔
474
        this->entries_.insert({map_stmt, this->users_.at(s).get()});
1✔
475

476
        // Indvar
477
        auto v = boost::add_vertex(this->graph_);
1✔
478
        this->add_user(
1✔
479
            std::make_unique<User>(v, map_stmt->indvar()->get_name(), map_stmt, Use::WRITE));
1✔
480
        boost::add_edge(last, v, this->graph_);
1✔
481
        last = v;
1✔
482

483
        // Root
484
        auto subgraph = this->traverse(map_stmt->root());
1✔
485
        boost::add_edge(last, subgraph.first, this->graph_);
1✔
486

487
        // NOP
488
        auto t = boost::add_vertex(this->graph_);
1✔
489
        this->users_.insert({t, std::make_unique<User>(t, "", map_stmt, Use::NOP)});
1✔
490
        last = t;
1✔
491
        boost::add_edge(subgraph.second, last, this->graph_);
1✔
492
        this->exits_.insert({map_stmt, this->users_.at(t).get()});
1✔
493

494
        return {s, t};
1✔
495
    }
496

497
    throw std::invalid_argument("Invalid control flow node type");
×
498
};
923✔
499

500
Users::Users(StructuredSDFG& sdfg)
119✔
501
    : Analysis(sdfg), node_(sdfg.root()) {
119✔
502

503
      };
119✔
504

505
Users::Users(StructuredSDFG& sdfg, structured_control_flow::ControlFlowNode& node)
148✔
506
    : Analysis(sdfg), node_(node) {
74✔
507

508
      };
74✔
509

510
void Users::run(analysis::AnalysisManager& analysis_manager) {
193✔
511
    users_.clear();
193✔
512
    graph_.clear();
193✔
513
    source_ = nullptr;
193✔
514
    sink_ = nullptr;
193✔
515
    dom_tree_.clear();
193✔
516
    pdom_tree_.clear();
193✔
517
    users_by_sdfg_.clear();
193✔
518
    users_by_sdfg_loop_condition_.clear();
193✔
519
    users_by_sdfg_loop_init_.clear();
193✔
520
    users_by_sdfg_loop_update_.clear();
193✔
521

522
    reads_.clear();
193✔
523
    writes_.clear();
193✔
524
    views_.clear();
193✔
525
    moves_.clear();
193✔
526

527
    this->traverse(node_);
193✔
528
    if (this->users_.empty()) {
193✔
529
        return;
×
530
    }
531

532
    // Require a single source
533
    for (auto& entry : this->users_) {
4,286✔
534
        if (boost::in_degree(entry.first, this->graph_) == 0) {
4,093✔
535
            if (this->source_ != nullptr) {
193✔
536
                throw InvalidSDFGException("Users Analysis: Non-unique source node");
×
537
            }
538
            this->source_ = entry.second.get();
193✔
539
        }
193✔
540
    }
541
    if (this->source_ == nullptr) {
193✔
542
        throw InvalidSDFGException("Users Analysis: No source node");
×
543
    }
544

545
    std::list<User*> sinks;
193✔
546
    for (auto& entry : this->users_) {
4,286✔
547
        if (boost::out_degree(entry.first, this->graph_) == 0) {
4,093✔
548
            sinks.push_back(entry.second.get());
193✔
549
        }
193✔
550
    }
551
    if (sinks.size() == 0) {
193✔
552
        throw InvalidSDFGException("Users Analysis: No sink node");
×
553
    }
554
    if (sinks.size() > 1) {
193✔
555
        // add artificial sink
556
        auto v = boost::add_vertex(this->graph_);
×
557
        auto sink = std::make_unique<User>(v, "", nullptr, Use::NOP);
×
558
        this->users_.insert({v, std::move(sink)});
×
559
        for (auto sink : sinks) {
×
560
            boost::add_edge(sink->vertex_, v, this->graph_);
×
561
        }
562
        sinks.clear();
×
563

564
        this->sink_ = this->users_.at(v).get();
×
565
    } else {
×
566
        this->sink_ = sinks.front();
193✔
567
    }
568

569
    // Collect sub structures
570
    for (auto& entry : this->users_) {
4,286✔
571
        auto container = entry.second->container();
4,093✔
572
        switch (entry.second->use()) {
4,093✔
573
            case Use::READ: {
574
                if (this->reads_.find(container) == this->reads_.end()) {
1,627✔
575
                    this->reads_.insert({container, {}});
702✔
576
                }
702✔
577
                this->reads_[container].push_back(entry.second.get());
1,627✔
578
                break;
1,627✔
579
            }
580
            case Use::WRITE: {
581
                if (this->writes_.find(container) == this->writes_.end()) {
626✔
582
                    this->writes_.insert({container, {}});
421✔
583
                }
421✔
584
                this->writes_[container].push_back(entry.second.get());
626✔
585
                break;
626✔
586
            }
587
            case Use::VIEW: {
588
                if (this->views_.find(container) == this->views_.end()) {
2✔
589
                    this->views_.insert({container, {}});
2✔
590
                }
2✔
591
                this->views_[container].push_back(entry.second.get());
2✔
592
                break;
2✔
593
            }
594
            case Use::MOVE: {
595
                if (this->moves_.find(container) == this->moves_.end()) {
2✔
596
                    this->moves_.insert({container, {}});
2✔
597
                }
2✔
598
                this->moves_[container].push_back(entry.second.get());
2✔
599
                break;
2✔
600
            }
601
            default:
602
                break;
1,836✔
603
        }
604
    }
4,093✔
605
};
193✔
606

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

616
    return us;
×
617
};
×
618

619
std::vector<User*> Users::uses(const std::string& container) const {
1✔
620
    std::vector<User*> us;
1✔
621
    for (auto& entry : this->users_) {
10✔
622
        if (entry.second->container() != container) {
9✔
623
            continue;
7✔
624
        }
625
        if (entry.second->use() == Use::NOP) {
2✔
626
            continue;
×
627
        }
628
        us.push_back(entry.second.get());
2✔
629
    }
630

631
    return us;
1✔
632
};
1✔
633

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

643
    return us;
×
644
};
×
645

646
std::vector<User*> Users::writes(const std::string& container) const {
66✔
647
    if (this->writes_.find(container) == this->writes_.end()) {
66✔
648
        return {};
25✔
649
    } else {
650
        return this->writes_.at(container);
41✔
651
    }
652
};
66✔
653

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

663
    return us;
×
664
};
×
665

666
std::vector<User*> Users::reads(const std::string& container) const {
33✔
667
    if (this->reads_.find(container) == this->reads_.end()) {
33✔
668
        return {};
13✔
669
    } else {
670
        return this->reads_.at(container);
20✔
671
    }
672
};
33✔
673

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

683
    return us;
×
684
};
×
685

686
std::vector<User*> Users::views(const std::string& container) const {
71✔
687
    if (this->views_.find(container) == this->views_.end()) {
71✔
688
        return {};
71✔
689
    } else {
690
        return this->views_.at(container);
×
691
    }
692
};
71✔
693

694
std::vector<User*> Users::moves() const {
×
695
    std::vector<User*> us;
×
696
    for (auto& entry : this->users_) {
×
697
        if (entry.second->use() != Use::MOVE) {
×
698
            continue;
×
699
        }
700
        us.push_back(entry.second.get());
×
701
    }
702

703
    return us;
×
704
};
×
705

706
std::vector<User*> Users::moves(const std::string& container) const {
77✔
707
    if (this->moves_.find(container) == this->moves_.end()) {
77✔
708
        return {};
76✔
709
    } else {
710
        return this->moves_.at(container);
1✔
711
    }
712
};
77✔
713

714
/****** Domination Analysis ******/
715

716
const std::unordered_map<User*, User*>& Users::dominator_tree() {
×
717
    if (this->dom_tree_.empty()) {
×
718
        this->init_dom_tree();
×
719
    }
×
720
    return this->dom_tree_;
×
721
};
722

723
bool Users::dominates(User& user1, User& user) {
26✔
724
    if (this->dom_tree_.empty()) {
26✔
725
        this->init_dom_tree();
19✔
726
    }
19✔
727
    auto dominator = this->dom_tree_.at(&user);
26✔
728
    while (dominator != nullptr) {
88✔
729
        if (dominator == &user1) {
88✔
730
            return true;
26✔
731
        }
732
        dominator = this->dom_tree_.at(dominator);
62✔
733
    }
734
    return false;
×
735
};
26✔
736

737
const std::unordered_map<User*, User*>& Users::post_dominator_tree() {
×
738
    if (this->pdom_tree_.empty()) {
×
739
        this->init_dom_tree();
×
740
    }
×
741
    return this->pdom_tree_;
×
742
};
743

744
bool Users::post_dominates(User& user1, User& user) {
6✔
745
    if (this->pdom_tree_.empty()) {
6✔
746
        this->init_dom_tree();
×
747
    }
×
748
    auto dominator = this->pdom_tree_.at(&user);
6✔
749
    while (dominator != nullptr) {
12✔
750
        if (dominator == &user1) {
12✔
751
            return true;
6✔
752
        }
753
        dominator = this->pdom_tree_.at(dominator);
6✔
754
    }
755
    return false;
×
756
};
6✔
757

758
const std::unordered_set<User*> Users::all_uses_between(User& user1, User& user) {
99✔
759
    std::unordered_set<User*> uses;
99✔
760
    std::unordered_set<User*> visited;
99✔
761
    std::list<User*> queue = {&user};
99✔
762
    while (!queue.empty()) {
2,207✔
763
        auto current = queue.front();
2,108✔
764
        queue.pop_front();
2,108✔
765

766
        // Stop conditions
767
        if (current == &user1) {
2,108✔
768
            continue;
99✔
769
        }
770

771
        if (visited.find(current) != visited.end()) {
2,009✔
772
            continue;
205✔
773
        }
774
        visited.insert(current);
1,804✔
775

776
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
1,804✔
777
            uses.insert(current);
1,160✔
778
        }
1,160✔
779

780
        // Extend search
781
        // Backward search to utilize domination user1 over user
782
        auto [eb, ee] = boost::in_edges(current->vertex_, this->graph_);
1,804✔
783
        auto edges = std::ranges::subrange(eb, ee);
3,608✔
784
        for (auto edge : edges) {
3,813✔
785
            auto v = boost::source(edge, this->graph_);
2,009✔
786
            queue.push_back(this->users_.at(v).get());
2,009✔
787
        }
788
    }
789

790
    return uses;
99✔
791
};
99✔
792

793
const std::unordered_set<User*> Users::all_uses_after(User& user1) {
×
794
    std::unordered_set<User*> uses;
×
795
    std::unordered_set<User*> visited;
×
796
    std::list<User*> queue = {&user1};
×
797
    while (!queue.empty()) {
×
798
        auto current = queue.front();
×
799
        queue.pop_front();
×
800
        if (visited.find(current) != visited.end()) {
×
801
            continue;
×
802
        }
803
        visited.insert(current);
×
804

805
        if (current != &user1 && current->use() != Use::NOP) {
×
806
            uses.insert(current);
×
807
        }
×
808

809
        // Extend search
810
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
811
        auto edges = std::ranges::subrange(eb, ee);
×
812
        for (auto edge : edges) {
×
813
            auto v = boost::target(edge, this->graph_);
×
814
            queue.push_back(this->users_.at(v).get());
×
815
        }
816
    }
817

818
    return uses;
×
819
};
×
820

UNCOV
821
const std::unordered_set<User*> Users::sources(const std::string& container) const {
×
UNCOV
822
    auto source = this->source_;
×
823

UNCOV
824
    std::unordered_set<User*> sources;
×
UNCOV
825
    std::unordered_set<User*> visited;
×
UNCOV
826
    std::list<User*> queue = {source};
×
UNCOV
827
    while (!queue.empty()) {
×
UNCOV
828
        auto current = queue.front();
×
UNCOV
829
        queue.pop_front();
×
UNCOV
830
        if (visited.find(current) != visited.end()) {
×
831
            continue;
×
832
        }
UNCOV
833
        visited.insert(current);
×
834

UNCOV
835
        if (current->container() == container && current->use() != Use::NOP) {
×
UNCOV
836
            sources.insert(current);
×
UNCOV
837
            continue;
×
838
        }
839

840
        // Extend search
UNCOV
841
        auto [eb, ee] = boost::out_edges(current->vertex_, this->graph_);
×
UNCOV
842
        auto edges = std::ranges::subrange(eb, ee);
×
UNCOV
843
        for (auto edge : edges) {
×
UNCOV
844
            auto v = boost::target(edge, this->graph_);
×
UNCOV
845
            queue.push_back(this->users_.at(v).get());
×
846
        }
847
    }
848

UNCOV
849
    return sources;
×
UNCOV
850
};
×
851

852
/****** Happens-Before Analysis ******/
853

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

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

873
std::unordered_map<std::string, std::vector<data_flow::Subset>> Users::write_subsets() {
×
874
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
875
    for (auto& write : this->users_) {
×
876
        if (write.second->use() != Use::WRITE) {
×
877
            continue;
×
878
        }
879

880
        auto& data = write.second->container();
×
881
        if (writeset.find(data) == writeset.end()) {
×
882
            writeset[data] = std::vector<data_flow::Subset>();
×
883
        }
×
884
        auto& subsets = write.second->subsets();
×
885
        for (auto& subset : subsets) {
×
886
            writeset[data].push_back(subset);
×
887
        }
888
    }
×
889
    return writeset;
×
890
};
×
891

892
std::unordered_set<std::string> Users::locals(StructuredSDFG& sdfg,
74✔
893
                                              structured_control_flow::ControlFlowNode& node) {
894
    // Collect all node elements
895
    Users local_users(sdfg, node);
74✔
896
    analysis::AnalysisManager analysis_manager(sdfg_);
74✔
897
    local_users.run(analysis_manager);
74✔
898
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
74✔
899
    for (auto& entry : local_users.users_) {
1,757✔
900
        if (entry.second->use() == Use::NOP) {
1,683✔
901
            continue;
630✔
902
        }
903
        if (!sdfg.is_transient(entry.second->container())) {
1,053✔
904
            continue;
303✔
905
        }
906

907
        if (elements.find(entry.second->container()) == elements.end()) {
750✔
908
            elements[entry.second->container()] = {};
221✔
909
        }
221✔
910
        elements[entry.second->container()].insert(entry.second->element());
750✔
911
    }
912

913
    // Determine locals
914
    for (auto& entry : this->users_) {
3,156✔
915
        if (entry.second->use() == Use::NOP) {
3,082✔
916
            continue;
1,236✔
917
        }
918

919
        auto& container = entry.second->container();
1,846✔
920
        auto element = entry.second->element();
1,846✔
921
        if (elements.find(container) == elements.end()) {
1,846✔
922
            continue;
1,239✔
923
        }
924
        // used outside of node
925
        if (elements[container].find(element) == elements[container].end()) {
607✔
926
            elements.erase(container);
114✔
927
        }
114✔
928
    }
929

930
    std::unordered_set<std::string> locals;
74✔
931
    for (auto& entry : elements) {
181✔
932
        locals.insert(entry.first);
107✔
933
    }
934
    return locals;
74✔
935
};
74✔
936

937
UsersView::UsersView(Users& users, structured_control_flow::ControlFlowNode& node) : users_(users) {
85✔
938
    auto& entry = users.entries_.at(&node);
85✔
939
    auto& exit = users.exits_.at(&node);
85✔
940
    this->entry_ = entry;
85✔
941
    this->exit_ = exit;
85✔
942
    this->sub_users_ = users.all_uses_between(*entry, *exit);
85✔
943
};
85✔
944

945
std::vector<User*> UsersView::uses() const {
×
946
    std::vector<User*> us;
×
947
    for (auto& user : this->sub_users_) {
×
948
        if (user->use() == Use::NOP) {
×
949
            continue;
×
950
        }
951
        us.push_back(user);
×
952
    }
953

954
    return us;
×
955
};
×
956

957
std::vector<User*> UsersView::uses(const std::string& container) const {
10✔
958
    std::vector<User*> us;
10✔
959
    for (auto& user : this->sub_users_) {
75✔
960
        if (user->container() != container) {
65✔
961
            continue;
48✔
962
        }
963
        if (user->use() == Use::NOP) {
17✔
964
            continue;
×
965
        }
966
        us.push_back(user);
17✔
967
    }
968

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

972
std::vector<User*> UsersView::writes() const {
76✔
973
    std::vector<User*> us;
76✔
974
    for (auto& user : this->sub_users_) {
1,139✔
975
        if (user->use() != Use::WRITE) {
1,063✔
976
            continue;
823✔
977
        }
978
        us.push_back(user);
240✔
979
    }
980

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

984
std::vector<User*> UsersView::writes(const std::string& container) const {
97✔
985
    std::vector<User*> us;
97✔
986
    for (auto& user : this->sub_users_) {
2,542✔
987
        if (user->container() != container) {
2,445✔
988
            continue;
2,265✔
989
        }
990
        if (user->use() != Use::WRITE) {
180✔
991
            continue;
80✔
992
        }
993
        us.push_back(user);
100✔
994
    }
995

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

999
std::vector<User*> UsersView::reads() const {
73✔
1000
    std::vector<User*> us;
73✔
1001
    for (auto& user : this->sub_users_) {
1,125✔
1002
        if (user->use() != Use::READ) {
1,052✔
1003
            continue;
238✔
1004
        }
1005
        us.push_back(user);
814✔
1006
    }
1007

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

1011
std::vector<User*> UsersView::reads(const std::string& container) const {
90✔
1012
    std::vector<User*> us;
90✔
1013
    for (auto& user : this->sub_users_) {
2,465✔
1014
        if (user->container() != container) {
2,375✔
1015
            continue;
2,212✔
1016
        }
1017
        if (user->use() != Use::READ) {
163✔
1018
            continue;
82✔
1019
        }
1020
        us.push_back(user);
81✔
1021
    }
1022

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

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

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

1038
std::vector<User*> UsersView::views(const std::string& container) const {
1✔
1039
    std::vector<User*> us;
1✔
1040
    for (auto& user : this->sub_users_) {
24✔
1041
        if (user->container() != container) {
23✔
1042
            continue;
22✔
1043
        }
1044
        if (user->use() != Use::VIEW) {
1✔
1045
            continue;
1✔
1046
        }
1047
        us.push_back(user);
×
1048
    }
1049

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

1053
std::vector<User*> UsersView::moves() const {
73✔
1054
    std::vector<User*> us;
73✔
1055
    for (auto& user : this->sub_users_) {
1,125✔
1056
        if (user->use() != Use::MOVE) {
1,052✔
1057
            continue;
1,052✔
1058
        }
1059
        us.push_back(user);
×
1060
    }
1061

1062
    return us;
73✔
1063
};
73✔
1064

1065
std::vector<User*> UsersView::moves(const std::string& container) const {
5✔
1066
    std::vector<User*> us;
5✔
1067
    for (auto& user : this->sub_users_) {
120✔
1068
        if (user->container() != container) {
115✔
1069
            continue;
102✔
1070
        }
1071
        if (user->use() != Use::MOVE) {
13✔
1072
            continue;
13✔
1073
        }
1074
        us.push_back(user);
×
1075
    }
1076

1077
    return us;
5✔
1078
};
5✔
1079

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

1085
    auto dom_tree = this->users_.dominator_tree();
×
1086
    std::unordered_map<User*, User*> sub_dom_tree;
×
1087
    for (auto& entry : this->sub_users_) {
×
1088
        sub_dom_tree[entry] = dom_tree[entry];
×
1089
    }
1090
    sub_dom_tree[this->entry_] = nullptr;
×
1091
    return sub_dom_tree;
×
1092
};
×
1093

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

1106
std::unordered_map<User*, User*> UsersView::post_dominator_tree() {
×
1107
    if (!this->sub_pdom_tree_.empty()) {
×
1108
        return this->sub_pdom_tree_;
×
1109
    }
1110

1111
    auto pdom_tree = this->users_.post_dominator_tree();
×
1112
    std::unordered_map<User*, User*> sub_pdom_tree;
×
1113
    for (auto& entry : this->sub_users_) {
×
1114
        sub_pdom_tree[entry] = pdom_tree[entry];
×
1115
    }
1116
    sub_pdom_tree[this->exit_] = nullptr;
×
1117
    return sub_pdom_tree;
×
1118
};
×
1119

1120
bool UsersView::post_dominates(User& user1, User& user) {
×
1121
    auto pdom_tree = this->post_dominator_tree();
×
1122
    auto dominator = pdom_tree[&user];
×
1123
    while (dominator != nullptr) {
×
1124
        if (dominator == &user1) {
×
1125
            return true;
×
1126
        }
1127
        dominator = pdom_tree[dominator];
×
1128
    }
1129
    return false;
×
1130
};
×
1131

1132
std::unordered_set<User*> UsersView::all_uses_between(User& user1, User& user) {
×
1133
    assert(this->sub_users_.find(&user1) != this->sub_users_.end());
×
1134
    assert(this->sub_users_.find(&user) != this->sub_users_.end());
×
1135

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

1147
        if (current != &user1 && current != &user && current->use() != Use::NOP) {
×
1148
            uses.insert(current);
×
1149
        }
×
1150

1151
        // Stop conditions
1152
        if (current == exit_) {
×
1153
            continue;
×
1154
        }
1155

1156
        if (current == &user) {
×
1157
            continue;
×
1158
        }
1159

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

1169
    return uses;
×
1170
};
×
1171

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

1175
    std::unordered_set<User*> uses;
×
1176
    std::unordered_set<User*> visited;
×
1177
    std::list<User*> queue = {&user1};
×
1178
    while (!queue.empty()) {
×
1179
        auto current = queue.front();
×
1180
        queue.pop_front();
×
1181
        if (visited.find(current) != visited.end()) {
×
1182
            continue;
×
1183
        }
1184
        visited.insert(current);
×
1185

1186
        if (current != &user1 && current->use() != Use::NOP) {
×
1187
            uses.insert(current);
×
1188
        }
×
1189

1190
        if (current == exit_) {
×
1191
            continue;
×
1192
        }
1193

1194
        // Extend search
1195
        auto [eb, ee] = boost::out_edges(current->vertex_, this->users_.graph_);
×
1196
        auto edges = std::ranges::subrange(eb, ee);
×
1197
        for (auto edge : edges) {
×
1198
            auto v = boost::target(edge, this->users_.graph_);
×
1199
            queue.push_back(this->users_.users_.at(v).get());
×
1200
        }
1201
    }
1202

1203
    return uses;
×
1204
};
×
1205

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

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

1225
std::unordered_map<std::string, std::vector<data_flow::Subset>> UsersView::write_subsets() {
×
1226
    std::unordered_map<std::string, std::vector<data_flow::Subset>> writeset;
×
1227
    for (auto& write : this->sub_users_) {
×
1228
        if (write->use() != Use::WRITE) {
×
1229
            continue;
×
1230
        }
1231

1232
        auto& data = write->container();
×
1233
        if (writeset.find(data) == writeset.end()) {
×
1234
            writeset[data] = std::vector<data_flow::Subset>();
×
1235
        }
×
1236
        auto& subsets = write->subsets();
×
1237
        for (auto& subset : subsets) {
×
1238
            writeset[data].push_back(subset);
×
1239
        }
1240
    }
×
1241
    return writeset;
×
1242
};
×
1243

1244
std::unordered_set<std::string> UsersView::locals(StructuredSDFG& sdfg,
×
1245
                                                  structured_control_flow::ControlFlowNode& node) {
1246
    // Collect all node elements
1247
    Users local_users(sdfg, node);
×
1248
    analysis::AnalysisManager analysis_manager(users_.sdfg_);
×
1249
    local_users.run(analysis_manager);
×
1250
    std::unordered_map<std::string, std::unordered_set<Element*>> elements;
×
1251
    for (auto& entry : local_users.users_) {
×
1252
        if (entry.second->use() == Use::NOP) {
×
1253
            continue;
×
1254
        }
1255
        if (!sdfg.is_transient(entry.second->container())) {
×
1256
            continue;
×
1257
        }
1258

1259
        if (elements.find(entry.second->container()) == elements.end()) {
×
1260
            elements[entry.second->container()] = {};
×
1261
        }
×
1262
        elements[entry.second->container()].insert(entry.second->element());
×
1263
    }
1264

1265
    // Determine locals
1266
    for (auto& entry : this->sub_users_) {
×
1267
        if (entry->use() == Use::NOP) {
×
1268
            continue;
×
1269
        }
1270

1271
        auto& container = entry->container();
×
1272
        auto element = entry->element();
×
1273
        if (elements.find(container) == elements.end()) {
×
1274
            continue;
×
1275
        }
1276
        // used outside of node
1277
        if (elements[container].find(element) == elements[container].end()) {
×
1278
            elements.erase(container);
×
1279
        }
×
1280
    }
1281

1282
    std::unordered_set<std::string> locals;
×
1283
    for (auto& entry : elements) {
×
1284
        locals.insert(entry.first);
×
1285
    }
1286
    return locals;
×
1287
};
×
1288

1289
User* Users::get_user(const std::string& container, Element* element, Use use, bool is_init,
310✔
1290
                      bool is_condition, bool is_update) {
1291
    if (auto for_loop = dynamic_cast<structured_control_flow::For*>(element)) {
310✔
1292
        if (is_init) {
38✔
1293
            auto tmp = users_by_sdfg_loop_init_.at(container).at(for_loop).at(use);
10✔
1294
            return tmp;
10✔
1295
        } else if (is_condition) {
28✔
1296
            return users_by_sdfg_loop_condition_.at(container).at(for_loop).at(use);
10✔
1297
        } else if (is_update) {
18✔
1298
            return users_by_sdfg_loop_update_.at(container).at(for_loop).at(use);
18✔
1299
        }
1300
    }
×
1301
    auto tmp = users_by_sdfg_.at(container).at(element).at(use);
272✔
1302
    return tmp;
272✔
1303
}
310✔
1304

1305
void Users::add_user(std::unique_ptr<User> user) {
2,257✔
1306
    auto vertex = user->vertex_;
2,257✔
1307
    this->users_.insert({vertex, std::move(user)});
2,257✔
1308

1309
    auto user_ptr = this->users_.at(vertex).get();
2,257✔
1310
    auto* target_structure = &users_by_sdfg_;
2,257✔
1311
    if (auto for_user = dynamic_cast<ForUser*>(user_ptr)) {
2,257✔
1312
        auto for_loop = dynamic_cast<structured_control_flow::For*>(user_ptr->element());
847✔
1313
        if (for_loop == nullptr) {
847✔
1314
            throw std::invalid_argument("Invalid user type");
×
1315
        }
1316
        if (for_user->is_init()) {
847✔
1317
            target_structure = &users_by_sdfg_loop_init_;
206✔
1318
        } else if (for_user->is_condition()) {
847✔
1319
            target_structure = &users_by_sdfg_loop_condition_;
338✔
1320
        } else if (for_user->is_update()) {
641✔
1321
            target_structure = &users_by_sdfg_loop_update_;
303✔
1322
        } else {
303✔
1323
            throw std::invalid_argument("Invalid user type");
×
1324
        }
1325
    }
847✔
1326

1327
    if (target_structure->find(user_ptr->container()) == target_structure->end()) {
2,257✔
1328
        target_structure->insert({user_ptr->container(), {}});
1,228✔
1329
    }
1,228✔
1330
    if ((*target_structure)[user_ptr->container()].find(user_ptr->element()) ==
4,514✔
1331
        (*target_structure)[user_ptr->container()].end()) {
2,257✔
1332
        target_structure->at(user_ptr->container()).insert({user_ptr->element(), {}});
2,097✔
1333
    }
2,097✔
1334
    target_structure->at(user_ptr->container())
2,257✔
1335
        .at(user_ptr->element())
2,257✔
1336
        .insert({user_ptr->use(), user_ptr});
2,257✔
1337
}
2,257✔
1338

1339
}  // namespace analysis
1340
}  // 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

© 2025 Coveralls, Inc