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

daisytuner / sdfglib / 15612270835

12 Jun 2025 01:44PM UTC coverage: 60.871% (-0.8%) from 61.71%
15612270835

push

github

web-flow
Merge pull request #68 from daisytuner/loop-types

refactors symbolic analysis into polynomials, extreme values and cnf

638 of 862 new or added lines in 24 files covered. (74.01%)

334 existing lines in 20 files now uncovered.

6571 of 10795 relevant lines covered (60.87%)

100.35 hits per line

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

84.86
/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)) {
×
NEW
118
                    auto current_user = users.get_user(atom->get_name(), tasklet, Use::READ);
×
119
                    {
120
                        bool found = false;
×
121
                        for (auto& user : open_reads_after_writes) {
×
NEW
122
                            if (user.first->container() == atom->get_name()) {
×
123
                                user.second.insert(current_user);
×
124
                                found = true;
×
125
                            }
×
126
                        }
127
                        if (!found) {
×
128
                            open_reads.insert(current_user);
×
129
                        }
×
130
                    }
131
                }
132
            }
×
133
        }
70✔
134

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

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

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

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

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

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

207
    // Read Condition - Never written in body
208
    for (auto atom : symbolic::atoms(for_loop.condition())) {
19✔
209
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
10✔
210

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

223
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_for;
9✔
224
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_for;
9✔
225
    std::unordered_set<User*> open_reads_for;
9✔
226

227
    visit_sequence(users, for_loop.root(), open_reads_for, open_reads_after_writes_for,
9✔
228
                   closed_reads_after_writes_for);
229

230
    for (auto& entry : closed_reads_after_writes_for) {
9✔
231
        closed_reads_after_write.insert(entry);
×
232
    }
233

234
    // Read Update
235
    for (auto atom : symbolic::atoms(for_loop.update())) {
18✔
236
        auto current_user =
9✔
237
            users.get_user(atom->get_name(), &for_loop, Use::READ, false, false, true);
9✔
238

239
        // Add for body
240
        for (auto& user : open_reads_after_writes_for) {
14✔
241
            if (user.first->container() == atom->get_name()) {
5✔
242
                user.second.insert(current_user);
1✔
243
            }
1✔
244
        }
245

246
        // Add to outside
247
        bool found = false;
9✔
248
        for (auto& user : open_reads_after_writes) {
30✔
249
            if (user.first->container() == atom->get_name()) {
21✔
250
                user.second.insert(current_user);
16✔
251
                found = true;
16✔
252
            }
16✔
253
        }
254
        if (!found) {
9✔
255
            open_reads.insert(current_user);
1✔
256
        }
1✔
257
    }
9✔
258

259
    // Handle open reads of for
260
    for (auto open_read : open_reads_for) {
14✔
261
        // Add recursive
262
        for (auto& user : open_reads_after_writes_for) {
10✔
263
            if (user.first->container() == open_read->container()) {
5✔
264
                user.second.insert(open_read);
×
265
            }
×
266
        }
267

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

280
    // Merge open reads_after_writes
281
    for (auto& entry : open_reads_after_writes_for) {
14✔
282
        open_reads_after_writes.insert(entry);
5✔
283
    }
284
}
9✔
285

286
void HappensBeforeAnalysis::visit_if_else(
19✔
287
    analysis::Users& users, structured_control_flow::IfElse& if_else,
288
    std::unordered_set<User*>& open_reads,
289
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
290
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
291
    // Read Conditions
292
    for (size_t i = 0; i < if_else.size(); i++) {
56✔
293
        auto child = if_else.at(i).second;
37✔
294
        for (auto atom : symbolic::atoms(child)) {
70✔
295
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
33✔
296

297
            bool found = false;
33✔
298
            for (auto& user : open_reads_after_writes) {
64✔
299
                if (user.first->container() == atom->get_name()) {
31✔
300
                    user.second.insert(current_user);
16✔
301
                    found = true;
16✔
302
                }
16✔
303
            }
304
            if (!found) {
33✔
305
                open_reads.insert(current_user);
17✔
306
            }
17✔
307
        }
33✔
308
    }
37✔
309

310
    std::vector<std::unordered_set<User*>> open_reads_branches(if_else.size());
19✔
311
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>>
312
        open_reads_after_writes_branches(if_else.size());
19✔
313
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>>
314
        closed_reads_after_writes_branches(if_else.size());
19✔
315
    for (size_t i = 0; i < if_else.size(); i++) {
56✔
316
        auto& child = if_else.at(i).first;
37✔
317
        visit_sequence(users, child, open_reads_branches.at(i),
74✔
318
                       open_reads_after_writes_branches.at(i),
37✔
319
                       closed_reads_after_writes_branches.at(i));
37✔
320
    }
37✔
321

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

338
    // merge closed writes
339
    for (auto& closing : closed_reads_after_writes_branches) {
56✔
340
        for (auto& entry : closing) {
37✔
341
            closed_reads_after_write.insert(entry);
×
342
        }
343
    }
344

345
    // Close open reads_after_writes for complete branches
346
    if (if_else.is_complete()) {
19✔
347
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
348
        std::unordered_set<std::string> candidates;
16✔
349
        std::unordered_set<std::string> candidates_tmp;
16✔
350

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

364
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
365
            for (auto& entry : open_reads_after_writes_branches.at(i)) {
29✔
366
                if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
367
                    candidates_tmp.insert(entry.first->container());
10✔
368
                }
10✔
369
            }
370
            candidates.swap(candidates_tmp);
16✔
371
            candidates_tmp.clear();
16✔
372
        }
16✔
373

374
        for (auto& entry : open_reads_after_writes) {
29✔
375
            if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
376
                to_close.insert(entry);
5✔
377
            }
5✔
378
        }
379

380
        for (auto& entry : to_close) {
21✔
381
            open_reads_after_writes.erase(entry.first);
5✔
382
            closed_reads_after_write.insert(entry);
5✔
383
        }
384
    }
16✔
385

386
    // merge open reads_after_writes
387
    for (auto& branch : open_reads_after_writes_branches) {
56✔
388
        for (auto& entry : branch) {
68✔
389
            open_reads_after_writes.insert(entry);
31✔
390
        }
391
    }
392
}
19✔
393

394
void HappensBeforeAnalysis::visit_while(
12✔
395
    analysis::Users& users, structured_control_flow::While& while_loop,
396
    std::unordered_set<User*>& open_reads,
397
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
398
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
399
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_while;
12✔
400
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_while;
12✔
401
    std::unordered_set<User*> open_reads_while;
12✔
402

403
    visit_sequence(users, while_loop.root(), open_reads_while, open_reads_after_writes_while,
12✔
404
                   closed_reads_after_writes_while);
405

406
    for (auto& entry : closed_reads_after_writes_while) {
14✔
407
        closed_reads_after_write.insert(entry);
2✔
408
    }
409

410
    for (auto open_read : open_reads_while) {
20✔
411
        // Add recursively to loop
412
        for (auto& entry : open_reads_after_writes_while) {
19✔
413
            if (entry.first->container() == open_read->container()) {
11✔
414
                entry.second.insert(open_read);
6✔
415
            }
6✔
416
        }
417

418
        // Add to outside
419
        bool found = false;
8✔
420
        for (auto& entry : open_reads_after_writes) {
11✔
421
            if (entry.first->container() == open_read->container()) {
3✔
422
                entry.second.insert(open_read);
3✔
423
                found = true;
3✔
424
            }
3✔
425
        }
426
        if (!found) {
8✔
427
            open_reads.insert(open_read);
5✔
428
        }
5✔
429
    }
430

431
    // Keep open reads_after_writes open after loop
432
    for (auto& entry : open_reads_after_writes_while) {
31✔
433
        open_reads_after_writes.insert(entry);
19✔
434
    }
435
}
12✔
436

437
void HappensBeforeAnalysis::visit_return(
×
438
    analysis::Users& users, structured_control_flow::Return& return_statement,
439
    std::unordered_set<User*>& open_reads,
440
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
441
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
442
    // close all open reads_after_writes
443
    for (auto& entry : open_reads_after_writes) {
×
444
        closed_reads_after_write.insert(entry);
×
445
    }
446
    open_reads_after_writes.clear();
×
447
}
×
448

449
void HappensBeforeAnalysis::visit_map(
2✔
450
    analysis::Users& users, structured_control_flow::Map& map,
451
    std::unordered_set<User*>& open_reads,
452
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
453
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
454
    // write Init
455
    auto current_user = users.get_user(map.indvar()->get_name(), &map, Use::WRITE);
2✔
456

457
    open_reads_after_writes.insert({current_user, {}});
2✔
458

459
    std::unordered_map<User*, std::unordered_set<User*>> open_reads_after_writes_map;
2✔
460
    std::unordered_map<User*, std::unordered_set<User*>> closed_reads_after_writes_map;
2✔
461
    std::unordered_set<User*> open_reads_map;
2✔
462

463
    visit_sequence(users, map.root(), open_reads_map, open_reads_after_writes_map,
2✔
464
                   closed_reads_after_writes_map);
465

466
    for (auto& entry : closed_reads_after_writes_map) {
2✔
467
        closed_reads_after_write.insert(entry);
×
468
    }
469

470
    // Handle open reads of for
471
    for (auto open_read : open_reads_map) {
4✔
472
        // Add recursive
473
        for (auto& user : open_reads_after_writes_map) {
4✔
474
            if (user.first->container() == open_read->container()) {
2✔
475
                user.second.insert(open_read);
×
476
            }
×
477
        }
478

479
        bool found = false;
2✔
480
        for (auto& entry : open_reads_after_writes) {
4✔
481
            if (entry.first->container() == open_read->container()) {
2✔
482
                entry.second.insert(open_read);
2✔
483
                found = true;
2✔
484
            }
2✔
485
        }
486
        if (!found) {
2✔
487
            open_reads.insert(open_read);
×
488
        }
×
489
    }
490

491
    // Merge open reads_after_writes
492
    for (auto& entry : open_reads_after_writes_map) {
4✔
493
        open_reads_after_writes.insert(entry);
2✔
494
    }
495
}
2✔
496

497
void HappensBeforeAnalysis::visit_sequence(
119✔
498
    analysis::Users& users, structured_control_flow::Sequence& sequence,
499
    std::unordered_set<User*>& open_reads,
500
    std::unordered_map<User*, std::unordered_set<User*>>& open_reads_after_writes,
501
    std::unordered_map<User*, std::unordered_set<User*>>& closed_reads_after_write) {
502
    for (size_t i = 0; i < sequence.size(); i++) {
288✔
503
        auto child = sequence.at(i);
169✔
504
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
169✔
505
            visit_block(users, *block, open_reads, open_reads_after_writes,
242✔
506
                        closed_reads_after_write);
121✔
507
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
169✔
508
            visit_for(users, *for_loop, open_reads, open_reads_after_writes,
16✔
509
                      closed_reads_after_write);
8✔
510
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
48✔
511
            visit_if_else(users, *if_else, open_reads, open_reads_after_writes,
36✔
512
                          closed_reads_after_write);
18✔
513
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
40✔
514
            visit_while(users, *while_loop, open_reads, open_reads_after_writes,
22✔
515
                        closed_reads_after_write);
11✔
516
        } else if (auto return_statement =
22✔
517
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
11✔
518
            visit_return(users, *return_statement, open_reads, open_reads_after_writes,
×
519
                         closed_reads_after_write);
×
520
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
11✔
521
            visit_sequence(users, *sequence, open_reads, open_reads_after_writes,
×
522
                           closed_reads_after_write);
×
523
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
11✔
524
            visit_map(users, *map, open_reads, open_reads_after_writes, closed_reads_after_write);
1✔
525
        }
1✔
526

527
        // handle transitions read
528
        for (auto& entry : child.second.assignments()) {
230✔
529
            for (auto& atom : symbolic::atoms(entry.second)) {
89✔
530
                if (symbolic::is_pointer(atom)) {
28✔
UNCOV
531
                    continue;
×
532
                }
533
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
28✔
534

535
                bool found = false;
28✔
536
                for (auto& user : open_reads_after_writes) {
52✔
537
                    if (user.first->container() == atom->get_name()) {
24✔
538
                        user.second.insert(current_user);
21✔
539
                        found = true;
21✔
540
                    }
21✔
541
                }
542
                if (!found) {
28✔
543
                    open_reads.insert(current_user);
13✔
544
                }
13✔
545
            }
546
        }
547

548
        // handle transitions write
549
        for (auto& entry : child.second.assignments()) {
230✔
550
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
61✔
551

552
            std::unordered_set<User*> to_close;
61✔
553
            for (auto& user : open_reads_after_writes) {
86✔
554
                if (user.first->container() == entry.first->get_name()) {
25✔
555
                    to_close.insert(user.first);
×
556
                }
×
557
            }
558
            for (auto& user : to_close) {
61✔
559
                closed_reads_after_write.insert({user, open_reads_after_writes.at(user)});
×
560
                open_reads_after_writes.erase(user);
×
561
            }
562
            open_reads_after_writes.insert({current_user, {}});
61✔
563
        }
61✔
564
    }
169✔
565
}
119✔
566

567
std::unordered_set<User*> HappensBeforeAnalysis::reads_after_write(User& write) {
×
568
    assert(write.use() == Use::WRITE);
×
569
    if (results_.find(write.container()) == results_.end()) {
×
570
        return {};
×
571
    }
572
    auto& raws = results_.at(write.container());
×
573
    assert(raws.find(&write) != raws.end());
×
574

575
    auto& reads_for_write = raws.at(&write);
×
576

577
    std::unordered_set<User*> reads;
×
578
    for (auto& entry : reads_for_write) {
×
579
        reads.insert(entry);
×
580
    }
581

582
    return reads;
×
583
};
×
584

585
std::unordered_map<User*, std::unordered_set<User*>> HappensBeforeAnalysis::reads_after_writes(
37✔
586
    const std::string& container) {
587
    if (results_.find(container) == results_.end()) {
37✔
588
        return {};
1✔
589
    }
590
    return results_.at(container);
36✔
591
};
37✔
592

593
std::unordered_map<User*, std::unordered_set<User*>>
594
HappensBeforeAnalysis::reads_after_write_groups(const std::string& container) {
19✔
595
    auto reads = this->reads_after_writes(container);
19✔
596

597
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
598
    for (auto& entry : reads) {
43✔
599
        for (auto& read : entry.second) {
51✔
600
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
601
                read_to_writes_map[read] = {};
20✔
602
            }
20✔
603
            read_to_writes_map[read].insert(entry.first);
27✔
604
        }
605
    }
606
    return read_to_writes_map;
19✔
607
};
19✔
608

609
}  // namespace analysis
610
}  // 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