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

daisytuner / sdfglib / 15262928007

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

push

github

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

Introduces new definition of memlets plus sanity checks

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

241 existing lines in 15 files now uncovered.

7908 of 13568 relevant lines covered (58.28%)

96.1 hits per line

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

83.29
/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)
50✔
20
    : Analysis(sdfg), node_(sdfg.root()) {
50✔
21

22
      };
50✔
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) {
50✔
31
    results_.clear();
50✔
32

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

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

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

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

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

54
void HappensBeforeAnalysis::visit_block(
124✔
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();
124✔
60

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

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

75
                    if (use == Use::WRITE) {
69✔
76
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
68✔
77
                        for (auto& user : open_reads_after_writes) {
93✔
78
                            if (user.first->container() == access_node->data()) {
25✔
79
                                to_close.insert(user);
5✔
80
                            }
5✔
81
                        }
82
                        for (auto& user : to_close) {
73✔
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, {}});
68✔
87
                    }
68✔
88
                }
69✔
89
                if (dataflow.out_degree(*access_node) > 0) {
123✔
90
                    Use use = Use::READ;
64✔
91
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
129✔
92
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
66✔
93
                            use = Use::VIEW;
1✔
94
                            break;
1✔
95
                        }
96
                    }
97

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

100
                    if (use == Use::READ) {
64✔
101
                        bool found = false;
63✔
102
                        for (auto& user : open_reads_after_writes) {
86✔
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) {
63✔
109
                            open_reads.insert(current_user);
49✔
110
                        }
49✔
111
                    }
63✔
112
                }
64✔
113
            }
123✔
114
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
191✔
115
            if (tasklet->is_conditional()) {
68✔
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
        }
68✔
135

136
        for (auto& oedge : dataflow.out_edges(*node)) {
325✔
137
            std::unordered_set<std::string> used;
134✔
138
            for (auto& dim : oedge.subset()) {
145✔
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) {
145✔
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
        }
134✔
161
    }
162
}
124✔
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

UNCOV
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) {
UNCOV
460
    visit_sequence(users, kernel.root(), open_reads, open_reads_after_writes,
×
UNCOV
461
                   closed_reads_after_write);
×
UNCOV
462
}
×
463

464
void HappensBeforeAnalysis::visit_sequence(
116✔
465
    analysis::Users& users, structured_control_flow::Sequence& sequence,
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
    for (size_t i = 0; i < sequence.size(); i++) {
282✔
470
        auto child = sequence.at(i);
166✔
471
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
166✔
472
            visit_block(users, *block, open_reads, open_reads_after_writes,
238✔
473
                        closed_reads_after_write);
119✔
474
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
166✔
475
            visit_for(users, *for_loop, open_reads, open_reads_after_writes,
16✔
476
                      closed_reads_after_write);
8✔
477
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
47✔
478
            visit_if_else(users, *if_else, open_reads, open_reads_after_writes,
36✔
479
                          closed_reads_after_write);
18✔
480
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
39✔
481
            visit_while(users, *while_loop, open_reads, open_reads_after_writes,
22✔
482
                        closed_reads_after_write);
11✔
483
        } else if (auto return_statement =
21✔
484
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
10✔
485
            visit_return(users, *return_statement, open_reads, open_reads_after_writes,
×
486
                         closed_reads_after_write);
×
487
        } else if (auto kernel = dynamic_cast<structured_control_flow::Kernel*>(&child.first)) {
10✔
UNCOV
488
            visit_kernel(users, *kernel, open_reads, open_reads_after_writes,
×
UNCOV
489
                         closed_reads_after_write);
×
490
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
10✔
491
            visit_sequence(users, *sequence, open_reads, open_reads_after_writes,
×
492
                           closed_reads_after_write);
×
493
        }
×
494

495
        // handle transitions read
496
        for (auto& entry : child.second.assignments()) {
227✔
497
            for (auto& atom : symbolic::atoms(entry.second)) {
89✔
498
                auto sym = SymEngine::rcp_dynamic_cast<const SymEngine::Symbol>(atom);
28✔
499
                if (symbolic::is_pointer(sym)) {
28✔
500
                    continue;
×
501
                }
502
                auto current_user = users.get_user(sym->get_name(), &child.second, Use::READ);
28✔
503

504
                bool found = false;
28✔
505
                for (auto& user : open_reads_after_writes) {
52✔
506
                    if (user.first->container() == sym->get_name()) {
24✔
507
                        user.second.insert(current_user);
21✔
508
                        found = true;
21✔
509
                    }
21✔
510
                }
511
                if (!found) {
28✔
512
                    open_reads.insert(current_user);
13✔
513
                }
13✔
514
            }
28✔
515
        }
516

517
        // handle transitions write
518
        for (auto& entry : child.second.assignments()) {
227✔
519
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
61✔
520

521
            std::unordered_set<User*> to_close;
61✔
522
            for (auto& user : open_reads_after_writes) {
86✔
523
                if (user.first->container() == entry.first->get_name()) {
25✔
524
                    to_close.insert(user.first);
×
525
                }
×
526
            }
527
            for (auto& user : to_close) {
61✔
528
                closed_reads_after_write.insert({user, open_reads_after_writes.at(user)});
×
529
                open_reads_after_writes.erase(user);
×
530
            }
531
            open_reads_after_writes.insert({current_user, {}});
61✔
532
        }
61✔
533
    }
166✔
534
}
116✔
535

536
std::unordered_set<User*> HappensBeforeAnalysis::reads_after_write(User& write) {
×
537
    assert(write.use() == Use::WRITE);
×
538
    if (results_.find(write.container()) == results_.end()) {
×
539
        return {};
×
540
    }
541
    auto& raws = results_.at(write.container());
×
542
    assert(raws.find(&write) != raws.end());
×
543

544
    auto& reads_for_write = raws.at(&write);
×
545

546
    std::unordered_set<User*> reads;
×
547
    for (auto& entry : reads_for_write) {
×
548
        reads.insert(entry);
×
549
    }
550

551
    return reads;
×
552
};
×
553

554
std::unordered_map<User*, std::unordered_set<User*>> HappensBeforeAnalysis::reads_after_writes(
37✔
555
    const std::string& container) {
556
    if (results_.find(container) == results_.end()) {
37✔
557
        return {};
1✔
558
    }
559
    return results_.at(container);
36✔
560
};
37✔
561

562
std::unordered_map<User*, std::unordered_set<User*>>
563
HappensBeforeAnalysis::reads_after_write_groups(const std::string& container) {
19✔
564
    auto reads = this->reads_after_writes(container);
19✔
565

566
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
567
    for (auto& entry : reads) {
43✔
568
        for (auto& read : entry.second) {
51✔
569
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
570
                read_to_writes_map[read] = {};
20✔
571
            }
20✔
572
            read_to_writes_map[read].insert(entry.first);
27✔
573
        }
574
    }
575
    return read_to_writes_map;
19✔
576
};
19✔
577

578
}  // namespace analysis
579
}  // 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