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

daisytuner / sdfglib / 15340968114

30 May 2025 06:47AM UTC coverage: 58.553% (+0.2%) from 58.324%
15340968114

push

github

web-flow
Add parallel Map node

* Introduce Map data structure

* Prepare infrastructure

* implement analysis support

* Add basic infrastructure

* visualizer/serializer

* include fix

* update from main

* remove default

* happens before test + fixes

* builder test

* dispatcher test

* visitor, copy and serializer tests

* for2map structures

* for2map conversion draft

* add tests

* Bug fixes

* small updates from feedback

* Visitor style pass implementation

* cleanup

* fixes linting errors

---------

Co-authored-by: Lukas Truemper <lukas.truemper@outlook.de>

258 of 381 new or added lines in 26 files covered. (67.72%)

17 existing lines in 14 files now uncovered.

8184 of 13977 relevant lines covered (58.55%)

109.83 hits per line

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

83.46
/src/analysis/happens_before_analysis.cpp
1
#include "sdfg/analysis/happens_before_analysis.h"
2

3
#include <cassert>
4
#include <string>
5
#include <unordered_map>
6
#include <unordered_set>
7
#include <vector>
8

9
#include "sdfg/analysis/analysis.h"
10
#include "sdfg/data_flow/memlet.h"
11
#include "sdfg/structured_control_flow/for.h"
12
#include "sdfg/structured_control_flow/sequence.h"
13
#include "sdfg/structured_sdfg.h"
14
#include "sdfg/symbolic/symbolic.h"
15

16
namespace sdfg {
17
namespace analysis {
18

19
HappensBeforeAnalysis::HappensBeforeAnalysis(StructuredSDFG& sdfg)
51✔
20
    : Analysis(sdfg), node_(sdfg.root()) {
51✔
21

22
      };
51✔
23

24
HappensBeforeAnalysis::HappensBeforeAnalysis(StructuredSDFG& sdfg,
×
25
                                             structured_control_flow::Sequence& node)
26
    : Analysis(sdfg), node_(node) {
×
27

28
      };
×
29

30
void HappensBeforeAnalysis::run(analysis::AnalysisManager& analysis_manager) {
51✔
31
    results_.clear();
51✔
32

33
    std::unordered_set<User*> open_reads;
51✔
34
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes;
51✔
35
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_write;
51✔
36

37
    auto& users = analysis_manager.get<Users>();
51✔
38
    visit_sequence(users, node_, open_reads, open_reads_after_writes, closed_reads_after_write);
51✔
39

40
    for (auto& entry : open_reads_after_writes) {
153✔
41
        closed_reads_after_write.insert(entry);
102✔
42
    }
43

44
    for (auto& entry : closed_reads_after_write) {
162✔
45
        if (results_.find(entry.first->container()) == results_.end()) {
111✔
46
            results_.insert({entry.first->container(), {}});
80✔
47
        }
80✔
48
        results_.at(entry.first->container()).insert(entry);
111✔
49
    }
50
};
51✔
51

52
/****** Visitor API ******/
53

54
void HappensBeforeAnalysis::visit_block(
126✔
55
    analysis::Users& users, structured_control_flow::Block& block,
56
    std::unordered_set<User*>& open_reads,
57
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
58
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
59
    auto& dataflow = block.dataflow();
126✔
60

61
    for (auto node : dataflow.topological_sort()) {
323✔
62
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
197✔
63
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
127✔
64
                if (dataflow.in_degree(*node) > 0) {
127✔
65
                    Use use = Use::WRITE;
71✔
66
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
141✔
67
                        if (iedge.src_conn() == "refs" || iedge.dst_conn() == "refs") {
71✔
68
                            use = Use::MOVE;
1✔
69
                            break;
1✔
70
                        }
71
                    }
72

73
                    auto current_user = users.get_user(access_node->data(), access_node, use);
71✔
74

75
                    if (use == Use::WRITE) {
71✔
76
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
70✔
77
                        for (auto& user : open_reads_after_writes) {
95✔
78
                            if (user.first->container() == access_node->data()) {
25✔
79
                                to_close.insert(user);
5✔
80
                            }
5✔
81
                        }
82
                        for (auto& user : to_close) {
75✔
83
                            open_reads_after_writes.erase(user.first);
5✔
84
                            closed_reads_after_write.insert(user);
5✔
85
                        }
86
                        open_reads_after_writes.insert({current_user, {}});
70✔
87
                    }
70✔
88
                }
71✔
89
                if (dataflow.out_degree(*access_node) > 0) {
127✔
90
                    Use use = Use::READ;
66✔
91
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
133✔
92
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
68✔
93
                            use = Use::VIEW;
1✔
94
                            break;
1✔
95
                        }
96
                    }
97

98
                    auto current_user = users.get_user(access_node->data(), access_node, use);
66✔
99

100
                    if (use == Use::READ) {
66✔
101
                        bool found = false;
65✔
102
                        for (auto& user : open_reads_after_writes) {
88✔
103
                            if (user.first->container() == access_node->data()) {
23✔
104
                                user.second.insert(current_user);
14✔
105
                                found = true;
14✔
106
                            }
14✔
107
                        }
108
                        if (!found) {
65✔
109
                            open_reads.insert(current_user);
51✔
110
                        }
51✔
111
                    }
65✔
112
                }
66✔
113
            }
127✔
114
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
197✔
115
            if (tasklet->is_conditional()) {
70✔
116
                auto& condition = tasklet->condition();
×
117
                for (auto& atom : symbolic::atoms(condition)) {
×
118
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
×
119
                    auto current_user = users.get_user(sym->get_name(), tasklet, Use::READ);
×
120
                    {
121
                        bool found = false;
×
122
                        for (auto& user : open_reads_after_writes) {
×
123
                            if (user.first->container() == sym->get_name()) {
×
124
                                user.second.insert(current_user);
×
125
                                found = true;
×
126
                            }
×
127
                        }
128
                        if (!found) {
×
129
                            open_reads.insert(current_user);
×
130
                        }
×
131
                    }
132
                }
×
133
            }
×
134
        }
70✔
135

136
        for (auto& oedge : dataflow.out_edges(*node)) {
335✔
137
            std::unordered_set<std::string> used;
138✔
138
            for (auto& dim : oedge.subset()) {
149✔
139
                for (auto atom : symbolic::atoms(dim)) {
22✔
140
                    auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
11✔
141
                    used.insert(sym->get_name());
11✔
142
                }
11✔
143
            }
144
            for (auto& sym : used) {
149✔
145
                auto current_user = users.get_user(sym, &oedge, Use::READ);
11✔
146

147
                {
148
                    bool found = false;
11✔
149
                    for (auto& user : open_reads_after_writes) {
13✔
150
                        if (user.first->container() == sym) {
2✔
151
                            user.second.insert(current_user);
2✔
152
                            found = true;
2✔
153
                        }
2✔
154
                    }
155
                    if (!found) {
11✔
156
                        open_reads.insert(current_user);
9✔
157
                    }
9✔
158
                }
159
            }
160
        }
138✔
161
    }
162
}
126✔
163

164
void HappensBeforeAnalysis::visit_for(
9✔
165
    analysis::Users& users, structured_control_flow::For& for_loop,
166
    std::unordered_set<User*>& open_reads,
167
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
168
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
169
    // Read Init
170
    for (auto atom : symbolic::atoms(for_loop.init())) {
10✔
171
        auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
1✔
172
        auto current_user = users.get_user(sym->get_name(), &for_loop, Use::READ, true);
1✔
173

174
        bool found = false;
1✔
175
        for (auto& user : open_reads_after_writes) {
2✔
176
            if (user.first->container() == sym->get_name()) {
1✔
177
                user.second.insert(current_user);
1✔
178
                found = true;
1✔
179
            }
1✔
180
        }
181
        if (!found) {
1✔
182
            open_reads.insert(current_user);
×
183
        }
×
184
    }
1✔
185

186
    {
187
        // Write Induction Variable
188
        auto current_user =
9✔
189
            users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, true);
9✔
190

191
        std::unordered_set<User*> to_close;
9✔
192
        for (auto& user : open_reads_after_writes) {
14✔
193
            if (user.first->container() == for_loop.indvar()->get_name()) {
5✔
194
                to_close.insert(user.first);
2✔
195
            }
2✔
196
        }
197
        for (auto& user : to_close) {
11✔
198
            closed_reads_after_write.insert({user, open_reads_after_writes.at(user)});
2✔
199
            open_reads_after_writes.erase(user);
2✔
200
        }
201
        open_reads_after_writes.insert({current_user, {}});
9✔
202
    }
9✔
203
    {
204
        // Write Update
205
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE,
9✔
206
                                           false, false, true);
207
        open_reads_after_writes.insert({current_user, {}});
9✔
208
    }
209

210
    // Read Condition - Never written in body
211
    for (auto atom : symbolic::atoms(for_loop.condition())) {
19✔
212
        auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
10✔
213
        auto current_user = users.get_user(sym->get_name(), &for_loop, Use::READ, false, true);
10✔
214

215
        bool found = false;
10✔
216
        for (auto& user : open_reads_after_writes) {
34✔
217
            if (user.first->container() == sym->get_name()) {
24✔
218
                user.second.insert(current_user);
19✔
219
                found = true;
19✔
220
            }
19✔
221
        }
222
        if (!found) {
10✔
223
            open_reads.insert(current_user);
×
224
        }
×
225
    }
10✔
226

227
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_for;
9✔
228
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_for;
9✔
229
    std::unordered_set<User*> open_reads_for;
9✔
230

231
    visit_sequence(users, for_loop.root(), open_reads_for, open_reads_after_writes_for,
9✔
232
                   closed_reads_after_writes_for);
233

234
    for (auto& entry : closed_reads_after_writes_for) {
9✔
235
        closed_reads_after_write.insert(entry);
×
236
    }
237

238
    // Read Update
239
    for (auto atom : symbolic::atoms(for_loop.update())) {
18✔
240
        auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
9✔
241
        auto current_user =
9✔
242
            users.get_user(sym->get_name(), &for_loop, Use::READ, false, false, true);
9✔
243

244
        // Add for body
245
        for (auto& user : open_reads_after_writes_for) {
14✔
246
            if (user.first->container() == sym->get_name()) {
5✔
247
                user.second.insert(current_user);
1✔
248
            }
1✔
249
        }
250

251
        // Add to outside
252
        bool found = false;
9✔
253
        for (auto& user : open_reads_after_writes) {
30✔
254
            if (user.first->container() == sym->get_name()) {
21✔
255
                user.second.insert(current_user);
16✔
256
                found = true;
16✔
257
            }
16✔
258
        }
259
        if (!found) {
9✔
260
            open_reads.insert(current_user);
1✔
261
        }
1✔
262
    }
9✔
263

264
    // Handle open reads of for
265
    for (auto open_read : open_reads_for) {
14✔
266
        // Add recursive
267
        for (auto& user : open_reads_after_writes_for) {
10✔
268
            if (user.first->container() == open_read->container()) {
5✔
269
                user.second.insert(open_read);
×
270
            }
×
271
        }
272

273
        bool found = false;
5✔
274
        for (auto& entry : open_reads_after_writes) {
17✔
275
            if (entry.first->container() == open_read->container()) {
12✔
276
                entry.second.insert(open_read);
10✔
277
                found = true;
10✔
278
            }
10✔
279
        }
280
        if (!found) {
5✔
281
            open_reads.insert(open_read);
×
282
        }
×
283
    }
284

285
    // Merge open reads_after_writes
286
    for (auto& entry : open_reads_after_writes_for) {
14✔
287
        open_reads_after_writes.insert(entry);
5✔
288
    }
289
}
9✔
290

291
void HappensBeforeAnalysis::visit_if_else(
19✔
292
    analysis::Users& users, structured_control_flow::IfElse& if_else,
293
    std::unordered_set<User*>& open_reads,
294
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
295
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
296
    // Read Conditions
297
    for (size_t i = 0; i < if_else.size(); i++) {
56✔
298
        auto child = if_else.at(i).second;
37✔
299
        for (auto atom : symbolic::atoms(child)) {
70✔
300
            auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
33✔
301
            auto current_user = users.get_user(sym->get_name(), &if_else, Use::READ);
33✔
302

303
            bool found = false;
33✔
304
            for (auto& user : open_reads_after_writes) {
64✔
305
                if (user.first->container() == sym->get_name()) {
31✔
306
                    user.second.insert(current_user);
16✔
307
                    found = true;
16✔
308
                }
16✔
309
            }
310
            if (!found) {
33✔
311
                open_reads.insert(current_user);
17✔
312
            }
17✔
313
        }
33✔
314
    }
37✔
315

316
    std::vector<std::unordered_set<User*>> open_reads_branches(if_else.size());
19✔
317
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>>
318
        open_reads_after_writes_branches(if_else.size());
19✔
319
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>>
320
        closed_reads_after_writes_branches(if_else.size());
19✔
321
    for (size_t i = 0; i < if_else.size(); i++) {
56✔
322
        auto& child = if_else.at(i).first;
37✔
323
        visit_sequence(users, child, open_reads_branches.at(i),
74✔
324
                       open_reads_after_writes_branches.at(i),
37✔
325
                       closed_reads_after_writes_branches.at(i));
37✔
326
    }
37✔
327

328
    // merge partial open reads
329
    for (size_t i = 0; i < if_else.size(); i++) {
56✔
330
        for (auto& entry : open_reads_branches.at(i)) {
55✔
331
            bool found = false;
18✔
332
            for (auto& entry2 : open_reads_after_writes) {
40✔
333
                if (entry2.first->container() == entry->container()) {
22✔
334
                    entry2.second.insert(entry);
14✔
335
                    found = true;
14✔
336
                }
14✔
337
            }
338
            if (!found) {
18✔
339
                open_reads.insert(entry);
4✔
340
            }
4✔
341
        }
342
    }
37✔
343

344
    // merge closed writes
345
    for (auto& closing : closed_reads_after_writes_branches) {
56✔
346
        for (auto& entry : closing) {
37✔
347
            closed_reads_after_write.insert(entry);
×
348
        }
349
    }
350

351
    // Close open reads_after_writes for complete branches
352
    if (if_else.is_complete()) {
19✔
353
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
354
        std::unordered_set<std::string> candidates;
16✔
355
        std::unordered_set<std::string> candidates_tmp;
16✔
356

357
        /* Complete close open reads_after_writes
358
        1. get candidates from first iteration
359
        2. iterate over all branches and prune candidates
360
        3. find prior writes for remaining candidates
361
        4. close open reads_after_writes for all candidates
362
        */
363
        for (auto& entry : open_reads_after_writes_branches.at(0)) {
29✔
364
            candidates.insert(entry.first->container());
13✔
365
        }
366
        for (auto& entry : closed_reads_after_writes_branches.at(0)) {
16✔
367
            candidates.insert(entry.first->container());
×
368
        }
369

370
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
371
            for (auto& entry : open_reads_after_writes_branches.at(i)) {
29✔
372
                if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
373
                    candidates_tmp.insert(entry.first->container());
10✔
374
                }
10✔
375
            }
376
            candidates.swap(candidates_tmp);
16✔
377
            candidates_tmp.clear();
16✔
378
        }
16✔
379

380
        for (auto& entry : open_reads_after_writes) {
29✔
381
            if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
382
                to_close.insert(entry);
5✔
383
            }
5✔
384
        }
385

386
        for (auto& entry : to_close) {
21✔
387
            open_reads_after_writes.erase(entry.first);
5✔
388
            closed_reads_after_write.insert(entry);
5✔
389
        }
390
    }
16✔
391

392
    // merge open reads_after_writes
393
    for (auto& branch : open_reads_after_writes_branches) {
56✔
394
        for (auto& entry : branch) {
68✔
395
            open_reads_after_writes.insert(entry);
31✔
396
        }
397
    }
398
}
19✔
399

400
void HappensBeforeAnalysis::visit_while(
12✔
401
    analysis::Users& users, structured_control_flow::While& while_loop,
402
    std::unordered_set<User*>& open_reads,
403
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
404
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
405
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_while;
12✔
406
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_while;
12✔
407
    std::unordered_set<User*> open_reads_while;
12✔
408

409
    visit_sequence(users, while_loop.root(), open_reads_while, open_reads_after_writes_while,
12✔
410
                   closed_reads_after_writes_while);
411

412
    for (auto& entry : closed_reads_after_writes_while) {
14✔
413
        closed_reads_after_write.insert(entry);
2✔
414
    }
415

416
    for (auto open_read : open_reads_while) {
20✔
417
        // Add recursively to loop
418
        for (auto& entry : open_reads_after_writes_while) {
19✔
419
            if (entry.first->container() == open_read->container()) {
11✔
420
                entry.second.insert(open_read);
6✔
421
            }
6✔
422
        }
423

424
        // Add to outside
425
        bool found = false;
8✔
426
        for (auto& entry : open_reads_after_writes) {
11✔
427
            if (entry.first->container() == open_read->container()) {
3✔
428
                entry.second.insert(open_read);
3✔
429
                found = true;
3✔
430
            }
3✔
431
        }
432
        if (!found) {
8✔
433
            open_reads.insert(open_read);
5✔
434
        }
5✔
435
    }
436

437
    // Keep open reads_after_writes open after loop
438
    for (auto& entry : open_reads_after_writes_while) {
31✔
439
        open_reads_after_writes.insert(entry);
19✔
440
    }
441
}
12✔
442

443
void HappensBeforeAnalysis::visit_return(
×
444
    analysis::Users& users, structured_control_flow::Return& return_statement,
445
    std::unordered_set<User*>& open_reads,
446
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
447
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
448
    // close all open reads_after_writes
449
    for (auto& entry : open_reads_after_writes) {
×
450
        closed_reads_after_write.insert(entry);
×
451
    }
452
    open_reads_after_writes.clear();
×
453
}
×
454

455
void HappensBeforeAnalysis::visit_kernel(
×
456
    analysis::Users& users, structured_control_flow::Kernel& kernel,
457
    std::unordered_set<User*>& open_reads,
458
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
459
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
460
    visit_sequence(users, kernel.root(), open_reads, open_reads_after_writes,
×
461
                   closed_reads_after_write);
×
462
}
×
463

464
void HappensBeforeAnalysis::visit_map(
2✔
465
    analysis::Users& users, structured_control_flow::Map& map,
466
    std::unordered_set<User*>& open_reads,
467
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
468
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
469
    // write Init
470
    auto current_user = users.get_user(map.indvar()->get_name(), &map, Use::WRITE);
2✔
471

472
    open_reads_after_writes.insert({current_user, {}});
2✔
473

474
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_map;
2✔
475
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_map;
2✔
476
    std::unordered_set<User*> open_reads_map;
2✔
477

478
    visit_sequence(users, map.root(), open_reads_map, open_reads_after_writes_map,
2✔
479
                   closed_reads_after_writes_map);
480

481
    for (auto& entry : closed_reads_after_writes_map) {
2✔
NEW
482
        closed_reads_after_write.insert(entry);
×
483
    }
484

485
    // Handle open reads of for
486
    for (auto open_read : open_reads_map) {
4✔
487
        // Add recursive
488
        for (auto& user : open_reads_after_writes_map) {
4✔
489
            if (user.first->container() == open_read->container()) {
2✔
NEW
490
                user.second.insert(open_read);
×
NEW
491
            }
×
492
        }
493

494
        bool found = false;
2✔
495
        for (auto& entry : open_reads_after_writes) {
4✔
496
            if (entry.first->container() == open_read->container()) {
2✔
497
                entry.second.insert(open_read);
2✔
498
                found = true;
2✔
499
            }
2✔
500
        }
501
        if (!found) {
2✔
NEW
502
            open_reads.insert(open_read);
×
NEW
503
        }
×
504
    }
505

506
    // Merge open reads_after_writes
507
    for (auto& entry : open_reads_after_writes_map) {
4✔
508
        open_reads_after_writes.insert(entry);
2✔
509
    }
510
}
2✔
511

512
void HappensBeforeAnalysis::visit_sequence(
119✔
513
    analysis::Users& users, structured_control_flow::Sequence& sequence,
514
    std::unordered_set<User*>& open_reads,
515
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
516
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
517
    for (size_t i = 0; i < sequence.size(); i++) {
288✔
518
        auto child = sequence.at(i);
169✔
519
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
169✔
520
            visit_block(users, *block, open_reads, open_reads_after_writes,
242✔
521
                        closed_reads_after_write);
121✔
522
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
169✔
523
            visit_for(users, *for_loop, open_reads, open_reads_after_writes,
16✔
524
                      closed_reads_after_write);
8✔
525
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
48✔
526
            visit_if_else(users, *if_else, open_reads, open_reads_after_writes,
36✔
527
                          closed_reads_after_write);
18✔
528
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
40✔
529
            visit_while(users, *while_loop, open_reads, open_reads_after_writes,
22✔
530
                        closed_reads_after_write);
11✔
531
        } else if (auto return_statement =
22✔
532
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
11✔
533
            visit_return(users, *return_statement, open_reads, open_reads_after_writes,
×
534
                         closed_reads_after_write);
×
535
        } else if (auto kernel = dynamic_cast<structured_control_flow::Kernel*>(&child.first)) {
11✔
536
            visit_kernel(users, *kernel, open_reads, open_reads_after_writes,
×
537
                         closed_reads_after_write);
×
538
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
11✔
539
            visit_sequence(users, *sequence, open_reads, open_reads_after_writes,
×
540
                           closed_reads_after_write);
×
541
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
11✔
542
            visit_map(users, *map, open_reads, open_reads_after_writes, closed_reads_after_write);
1✔
543
        }
1✔
544

545
        // handle transitions read
546
        for (auto& entry : child.second.assignments()) {
230✔
547
            for (auto& atom : symbolic::atoms(entry.second)) {
89✔
548
                auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
28✔
549
                if (symbolic::is_pointer(sym)) {
28✔
550
                    continue;
×
551
                }
552
                auto current_user = users.get_user(sym->get_name(), &child.second, Use::READ);
28✔
553

554
                bool found = false;
28✔
555
                for (auto& user : open_reads_after_writes) {
52✔
556
                    if (user.first->container() == sym->get_name()) {
24✔
557
                        user.second.insert(current_user);
21✔
558
                        found = true;
21✔
559
                    }
21✔
560
                }
561
                if (!found) {
28✔
562
                    open_reads.insert(current_user);
13✔
563
                }
13✔
564
            }
28✔
565
        }
566

567
        // handle transitions write
568
        for (auto& entry : child.second.assignments()) {
230✔
569
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
61✔
570

571
            std::unordered_set<User*> to_close;
61✔
572
            for (auto& user : open_reads_after_writes) {
86✔
573
                if (user.first->container() == entry.first->get_name()) {
25✔
574
                    to_close.insert(user.first);
×
575
                }
×
576
            }
577
            for (auto& user : to_close) {
61✔
578
                closed_reads_after_write.insert({user, open_reads_after_writes.at(user)});
×
579
                open_reads_after_writes.erase(user);
×
580
            }
581
            open_reads_after_writes.insert({current_user, {}});
61✔
582
        }
61✔
583
    }
169✔
584
}
119✔
585

586
std::unordered_set<User*> HappensBeforeAnalysis::reads_after_write(User& write) {
×
587
    assert(write.use() == Use::WRITE);
×
588
    if (results_.find(write.container()) == results_.end()) {
×
589
        return {};
×
590
    }
591
    auto& raws = results_.at(write.container());
×
592
    assert(raws.find(&write) != raws.end());
×
593

594
    auto& reads_for_write = raws.at(&write);
×
595

596
    std::unordered_set<User*> reads;
×
597
    for (auto& entry : reads_for_write) {
×
598
        reads.insert(entry);
×
599
    }
600

601
    return reads;
×
602
};
×
603

604
std::unordered_map<User*, std::unordered_set<User*>> HappensBeforeAnalysis::reads_after_writes(
37✔
605
    const std::string& container) {
606
    if (results_.find(container) == results_.end()) {
37✔
607
        return {};
1✔
608
    }
609
    return results_.at(container);
36✔
610
};
37✔
611

612
std::unordered_map<User*, std::unordered_set<User*>>
613
HappensBeforeAnalysis::reads_after_write_groups(const std::string& container) {
19✔
614
    auto reads = this->reads_after_writes(container);
19✔
615

616
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
617
    for (auto& entry : reads) {
43✔
618
        for (auto& read : entry.second) {
51✔
619
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
620
                read_to_writes_map[read] = {};
20✔
621
            }
20✔
622
            read_to_writes_map[read].insert(entry.first);
27✔
623
        }
624
    }
625
    return read_to_writes_map;
19✔
626
};
19✔
627

628
}  // namespace analysis
629
}  // 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