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

daisytuner / sdfglib / 15777275738

20 Jun 2025 10:49AM UTC coverage: 64.573% (-0.02%) from 64.591%
15777275738

Pull #95

github

web-flow
Merge 8fc903d42 into 37b47b09d
Pull Request #95: Extends Data Dependency Analysis

215 of 298 new or added lines in 8 files covered. (72.15%)

22 existing lines in 3 files now uncovered.

8213 of 12719 relevant lines covered (64.57%)

152.49 hits per line

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

76.91
/src/analysis/data_dependency_analysis.cpp
1
#include "sdfg/analysis/data_dependency_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/structured_sdfg.h"
11
#include "sdfg/symbolic/sets.h"
12

13
namespace sdfg {
14
namespace analysis {
15

16
DataDependencyAnalysis::DataDependencyAnalysis(StructuredSDFG& sdfg)
54✔
17
    : Analysis(sdfg), node_(sdfg.root()) {
54✔
18

19
      };
54✔
20

NEW
21
DataDependencyAnalysis::DataDependencyAnalysis(StructuredSDFG& sdfg,
×
22
                                               structured_control_flow::Sequence& node)
23
    : Analysis(sdfg), node_(node) {
×
24

25
      };
×
26

27
void DataDependencyAnalysis::run(analysis::AnalysisManager& analysis_manager) {
34✔
28
    results_.clear();
34✔
29

30
    std::unordered_set<User*> undefined;
34✔
31
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions;
34✔
32
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions;
34✔
33

34
    auto& users = analysis_manager.get<Users>();
34✔
35
    auto& assumptions_analysis = analysis_manager.get<AssumptionsAnalysis>();
34✔
36
    symbolic::Assumptions assumptions = assumptions_analysis.get(node_, true);
34✔
37
    visit_sequence(users, assumptions_analysis, assumptions, node_, undefined, open_definitions,
34✔
38
                   closed_definitions);
39

40
    for (auto& entry : open_definitions) {
100✔
41
        closed_definitions.insert(entry);
66✔
42
    }
43

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

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

54
void DataDependencyAnalysis::visit_block(
105✔
55
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
56
    symbolic::Assumptions& assumptions, structured_control_flow::Block& block,
57
    std::unordered_set<User*>& undefined,
58
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
59
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
60
    auto& dataflow = block.dataflow();
105✔
61

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

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

76
                    if (use == Use::WRITE) {
36✔
77
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
36✔
78
                        for (auto& user : open_definitions) {
60✔
79
                            if (overwrites(*user.first, *current_user, assumptions)) {
24✔
80
                                to_close.insert(user);
7✔
81
                            }
7✔
82
                        }
83
                        for (auto& user : to_close) {
43✔
84
                            open_definitions.erase(user.first);
7✔
85
                            closed_definitions.insert(user);
7✔
86
                        }
87
                        open_definitions.insert({current_user, {}});
36✔
88
                    }
36✔
89
                }
36✔
90
                if (dataflow.out_degree(*access_node) > 0) {
41✔
91
                    Use use = Use::READ;
8✔
92
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
16✔
93
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
8✔
94
                            use = Use::VIEW;
×
95
                            break;
×
96
                        }
97
                    }
98

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

101
                    if (use == Use::READ) {
8✔
102
                        bool found = false;
8✔
103
                        for (auto& user : open_definitions) {
11✔
104
                            if (reads(*user.first, *current_user, assumptions)) {
3✔
105
                                user.second.insert(current_user);
2✔
106
                                found = true;
2✔
107
                            }
2✔
108
                        }
109
                        if (!found) {
8✔
110
                            undefined.insert(current_user);
6✔
111
                        }
6✔
112
                    }
8✔
113
                }
8✔
114
            }
41✔
115
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
77✔
116
            if (tasklet->is_conditional()) {
36✔
117
                auto& condition = tasklet->condition();
×
118
                for (auto& atom : symbolic::atoms(condition)) {
×
119
                    auto current_user = users.get_user(atom->get_name(), tasklet, Use::READ);
×
120
                    {
121
                        bool found = false;
×
NEW
122
                        for (auto& user : open_definitions) {
×
NEW
123
                            if (reads(*user.first, *current_user, assumptions)) {
×
124
                                user.second.insert(current_user);
×
125
                                found = true;
×
126
                            }
×
127
                        }
128
                        if (!found) {
×
NEW
129
                            undefined.insert(current_user);
×
130
                        }
×
131
                    }
132
                }
133
            }
×
134
        }
36✔
135

136
        for (auto& oedge : dataflow.out_edges(*node)) {
121✔
137
            std::unordered_set<std::string> used;
44✔
138
            for (auto& dim : oedge.subset()) {
78✔
139
                for (auto atom : symbolic::atoms(dim)) {
39✔
140
                    used.insert(atom->get_name());
5✔
141
                }
5✔
142
            }
143
            for (auto& atom : used) {
49✔
144
                auto current_user = users.get_user(atom, &oedge, Use::READ);
5✔
145

146
                {
147
                    bool found = false;
5✔
148
                    for (auto& user : open_definitions) {
7✔
149
                        if (reads(*user.first, *current_user, assumptions)) {
2✔
150
                            user.second.insert(current_user);
2✔
151
                            found = true;
2✔
152
                        }
2✔
153
                    }
154
                    if (!found) {
5✔
155
                        undefined.insert(current_user);
3✔
156
                    }
3✔
157
                }
158
            }
159
        }
44✔
160
    }
161
}
105✔
162

163
void DataDependencyAnalysis::visit_for(
9✔
164
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
165
    symbolic::Assumptions& assumptions, structured_control_flow::For& for_loop,
166
    std::unordered_set<User*>& undefined,
167
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
168
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
169
    // Read Init
170
    for (auto atom : symbolic::atoms(for_loop.init())) {
10✔
171
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
1✔
172

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

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

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

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

213
        bool found = false;
10✔
214
        for (auto& user : open_definitions) {
32✔
215
            if (user.first->container() == atom->get_name()) {
22✔
216
                user.second.insert(current_user);
19✔
217
                found = true;
19✔
218
            }
19✔
219
        }
220
        if (!found) {
10✔
NEW
221
            undefined.insert(current_user);
×
222
        }
×
223
    }
10✔
224

225
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
9✔
226
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_for;
9✔
227
    std::unordered_set<User*> undefined_for;
9✔
228

229
    // Add assumptions for body
230
    symbolic::Assumptions body_assumptions = assumptions;
9✔
231
    assumptions_analysis.add(body_assumptions, for_loop.root());
9✔
232
    visit_sequence(users, assumptions_analysis, body_assumptions, for_loop.root(), undefined_for,
9✔
233
                   open_definitions_for, closed_definitionss_for);
234

235
    for (auto& entry : closed_definitionss_for) {
9✔
NEW
236
        closed_definitions.insert(entry);
×
237
    }
238

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

244
        // Add for body
245
        bool found = false;
9✔
246
        for (auto& user : open_definitions_for) {
13✔
247
            if (user.first->container() == atom->get_name()) {
4✔
248
                user.second.insert(current_user);
1✔
249
                found = true;
1✔
250
            }
1✔
251
        }
252

253
        // Add to outside
254
        if (!found) {
9✔
255
            for (auto& user : open_definitions) {
25✔
256
                if (user.first->container() == atom->get_name()) {
17✔
257
                    user.second.insert(current_user);
16✔
258
                    found = true;
16✔
259
                }
16✔
260
            }
261
            if (!found) {
8✔
NEW
262
                undefined.insert(current_user);
×
NEW
263
            }
×
264
        }
8✔
265
    }
9✔
266

267
    // Handle open reads of for
268
    for (auto open_read : undefined_for) {
12✔
269
        // Add recursive
270
        for (auto& user : open_definitions_for) {
6✔
271
            if (user.first->container() == open_read->container()) {
3✔
272
                user.second.insert(open_read);
×
273
            }
×
274
        }
275

276
        bool found = false;
3✔
277
        for (auto& entry : open_definitions) {
9✔
278
            if (entry.first->container() == open_read->container()) {
6✔
279
                entry.second.insert(open_read);
6✔
280
                found = true;
6✔
281
            }
6✔
282
        }
283
        if (!found) {
3✔
NEW
284
            undefined.insert(open_read);
×
285
        }
×
286
    }
287

288
    // Merge open reads_after_writes
289
    for (auto& entry : open_definitions_for) {
13✔
290
        open_definitions.insert(entry);
4✔
291
    }
292
}
9✔
293

294
void DataDependencyAnalysis::visit_if_else(
18✔
295
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
296
    symbolic::Assumptions& assumptions, structured_control_flow::IfElse& if_else,
297
    std::unordered_set<User*>& undefined,
298
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
299
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
300
    // Read Conditions
301
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
302
        auto child = if_else.at(i).second;
33✔
303
        for (auto atom : symbolic::atoms(child)) {
54✔
304
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
21✔
305

306
            bool found = false;
21✔
307
            for (auto& user : open_definitions) {
35✔
308
                if (user.first->container() == atom->get_name()) {
14✔
309
                    user.second.insert(current_user);
7✔
310
                    found = true;
7✔
311
                }
7✔
312
            }
313
            if (!found) {
21✔
314
                undefined.insert(current_user);
14✔
315
            }
14✔
316
        }
21✔
317
    }
33✔
318

319
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
18✔
320
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(
18✔
321
        if_else.size());
18✔
322
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(
18✔
323
        if_else.size());
18✔
324
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
325
        auto& child = if_else.at(i).first;
33✔
326

327
        // Add assumptions for child
328
        symbolic::Assumptions child_assumptions = assumptions;
33✔
329
        assumptions_analysis.add(child_assumptions, child);
33✔
330
        visit_sequence(users, assumptions_analysis, child_assumptions, child,
66✔
331
                       undefined_branches.at(i), open_definitions_branches.at(i),
33✔
332
                       closed_definitionss_branches.at(i));
33✔
333
    }
33✔
334

335
    // merge partial open reads
336
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
337
        for (auto& entry : undefined_branches.at(i)) {
37✔
338
            bool found = false;
4✔
339
            for (auto& entry2 : open_definitions) {
8✔
340
                if (entry2.first->container() == entry->container()) {
4✔
341
                    entry2.second.insert(entry);
4✔
342
                    found = true;
4✔
343
                }
4✔
344
            }
345
            if (!found) {
4✔
NEW
346
                undefined.insert(entry);
×
347
            }
×
348
        }
349
    }
33✔
350

351
    // merge closed writes
352
    for (auto& closing : closed_definitionss_branches) {
51✔
353
        for (auto& entry : closing) {
33✔
NEW
354
            closed_definitions.insert(entry);
×
355
        }
356
    }
357

358
    // Close open reads_after_writes for complete branches
359
    if (if_else.is_complete()) {
18✔
360
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
15✔
361
        std::unordered_set<std::string> candidates;
15✔
362
        std::unordered_set<std::string> candidates_tmp;
15✔
363

364
        /* Complete close open reads_after_writes
365
        1. get candidates from first iteration
366
        2. iterate over all branches and prune candidates
367
        3. find prior writes for remaining candidates
368
        4. close open reads_after_writes for all candidates
369
        */
370
        for (auto& entry : open_definitions_branches.at(0)) {
29✔
371
            candidates.insert(entry.first->container());
14✔
372
        }
373
        for (auto& entry : closed_definitionss_branches.at(0)) {
15✔
374
            candidates.insert(entry.first->container());
×
375
        }
376

377
        for (size_t i = 1; i < if_else.size(); i++) {
30✔
378
            for (auto& entry : open_definitions_branches.at(i)) {
28✔
379
                if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
380
                    candidates_tmp.insert(entry.first->container());
13✔
381
                }
13✔
382
            }
383
            candidates.swap(candidates_tmp);
15✔
384
            candidates_tmp.clear();
15✔
385
        }
15✔
386

387
        for (auto& entry : open_definitions) {
22✔
388
            if (candidates.find(entry.first->container()) != candidates.end()) {
7✔
389
                to_close.insert(entry);
3✔
390
            }
3✔
391
        }
392

393
        for (auto& entry : to_close) {
18✔
394
            open_definitions.erase(entry.first);
3✔
395
            closed_definitions.insert(entry);
3✔
396
        }
397
    }
15✔
398

399
    // merge open reads_after_writes
400
    for (auto& branch : open_definitions_branches) {
51✔
401
        for (auto& entry : branch) {
61✔
402
            open_definitions.insert(entry);
28✔
403
        }
404
    }
405
}
18✔
406

407
void DataDependencyAnalysis::visit_while(
7✔
408
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
409
    symbolic::Assumptions& assumptions, structured_control_flow::While& while_loop,
410
    std::unordered_set<User*>& undefined,
411
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
412
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
413
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
414
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_while;
7✔
415
    std::unordered_set<User*> undefined_while;
7✔
416

417
    // Add assumptions for body
418
    symbolic::Assumptions body_assumptions = assumptions;
7✔
419
    assumptions_analysis.add(body_assumptions, while_loop.root());
7✔
420
    visit_sequence(users, assumptions_analysis, body_assumptions, while_loop.root(),
7✔
421
                   undefined_while, open_definitions_while, closed_definitionss_while);
422

423
    for (auto& entry : closed_definitionss_while) {
9✔
424
        closed_definitions.insert(entry);
2✔
425
    }
426

427
    for (auto open_read : undefined_while) {
9✔
428
        // Add recursively to loop
429
        for (auto& entry : open_definitions_while) {
5✔
430
            if (entry.first->container() == open_read->container()) {
3✔
431
                entry.second.insert(open_read);
2✔
432
            }
2✔
433
        }
434

435
        // Add to outside
436
        bool found = false;
2✔
437
        for (auto& entry : open_definitions) {
3✔
438
            if (entry.first->container() == open_read->container()) {
1✔
439
                entry.second.insert(open_read);
1✔
440
                found = true;
1✔
441
            }
1✔
442
        }
443
        if (!found) {
2✔
444
            undefined.insert(open_read);
1✔
445
        }
1✔
446
    }
447

448
    // Keep open reads_after_writes open after loop
449
    for (auto& entry : open_definitions_while) {
19✔
450
        open_definitions.insert(entry);
12✔
451
    }
452
}
7✔
453

NEW
454
void DataDependencyAnalysis::visit_return(
×
455
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
456
    symbolic::Assumptions& assumptions, structured_control_flow::Return& return_statement,
457
    std::unordered_set<User*>& undefined,
458
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
459
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
460
    // close all open reads_after_writes
NEW
461
    for (auto& entry : open_definitions) {
×
NEW
462
        closed_definitions.insert(entry);
×
463
    }
NEW
464
    open_definitions.clear();
×
465
}
×
466

NEW
467
void DataDependencyAnalysis::visit_map(
×
468
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
469
    symbolic::Assumptions& assumptions, structured_control_flow::Map& map,
470
    std::unordered_set<User*>& undefined,
471
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
472
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
473
    // write Init
474
    auto current_user = users.get_user(map.indvar()->get_name(), &map, Use::WRITE);
×
475

NEW
476
    open_definitions.insert({current_user, {}});
×
477

NEW
478
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_map;
×
NEW
479
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_map;
×
NEW
480
    std::unordered_set<User*> undefined_map;
×
481

482
    // Add assumptions for body
NEW
483
    symbolic::Assumptions body_assumptions = assumptions;
×
NEW
484
    assumptions_analysis.add(body_assumptions, map.root());
×
NEW
485
    visit_sequence(users, assumptions_analysis, body_assumptions, map.root(), undefined_map,
×
486
                   open_definitions_map, closed_definitionss_map);
487

NEW
488
    for (auto& entry : closed_definitionss_map) {
×
NEW
489
        closed_definitions.insert(entry);
×
490
    }
491

492
    // Handle open reads of for
NEW
493
    for (auto open_read : undefined_map) {
×
494
        // Add recursive
NEW
495
        for (auto& user : open_definitions_map) {
×
496
            if (user.first->container() == open_read->container()) {
×
497
                user.second.insert(open_read);
×
498
            }
×
499
        }
500

501
        bool found = false;
×
NEW
502
        for (auto& entry : open_definitions) {
×
503
            if (entry.first->container() == open_read->container()) {
×
504
                entry.second.insert(open_read);
×
505
                found = true;
×
506
            }
×
507
        }
508
        if (!found) {
×
NEW
509
            undefined.insert(open_read);
×
510
        }
×
511
    }
512

513
    // Merge open reads_after_writes
NEW
514
    for (auto& entry : open_definitions_map) {
×
NEW
515
        open_definitions.insert(entry);
×
516
    }
517
}
×
518

519
void DataDependencyAnalysis::visit_sequence(
97✔
520
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
521
    symbolic::Assumptions& assumptions, structured_control_flow::Sequence& sequence,
522
    std::unordered_set<User*>& undefined,
523
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
524
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
525
    for (size_t i = 0; i < sequence.size(); i++) {
236✔
526
        auto child = sequence.at(i);
139✔
527

528
        // Add assumptions for child
529
        symbolic::Assumptions child_assumptions = assumptions;
139✔
530
        assumptions_analysis.add(child_assumptions, child.first);
139✔
531

532
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
139✔
533
            visit_block(users, assumptions_analysis, child_assumptions, *block, undefined,
194✔
534
                        open_definitions, closed_definitions);
97✔
535
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
139✔
536
            visit_for(users, assumptions_analysis, child_assumptions, *for_loop, undefined,
18✔
537
                      open_definitions, closed_definitions);
9✔
538
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
42✔
539
            visit_if_else(users, assumptions_analysis, child_assumptions, *if_else, undefined,
36✔
540
                          open_definitions, closed_definitions);
18✔
541
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
33✔
542
            visit_while(users, assumptions_analysis, child_assumptions, *while_loop, undefined,
14✔
543
                        open_definitions, closed_definitions);
7✔
544
        } else if (auto return_statement =
15✔
545
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
8✔
NEW
546
            visit_return(users, assumptions_analysis, child_assumptions, *return_statement,
×
NEW
547
                         undefined, open_definitions, closed_definitions);
×
548
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
NEW
549
            visit_sequence(users, assumptions_analysis, child_assumptions, *sequence, undefined,
×
NEW
550
                           open_definitions, closed_definitions);
×
551
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
8✔
NEW
552
            visit_map(users, assumptions_analysis, child_assumptions, *map, undefined,
×
NEW
553
                      open_definitions, closed_definitions);
×
554
        }
×
555

556
        // handle transitions read
557
        for (auto& entry : child.second.assignments()) {
201✔
558
            for (auto& atom : symbolic::atoms(entry.second)) {
84✔
559
                if (symbolic::is_pointer(atom)) {
22✔
560
                    continue;
×
561
                }
562
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
22✔
563

564
                bool found = false;
22✔
565
                for (auto& user : open_definitions) {
41✔
566
                    if (user.first->container() == atom->get_name()) {
19✔
567
                        user.second.insert(current_user);
18✔
568
                        found = true;
18✔
569
                    }
18✔
570
                }
571
                if (!found) {
22✔
572
                    undefined.insert(current_user);
10✔
573
                }
10✔
574
            }
575
        }
576

577
        // handle transitions write
578
        for (auto& entry : child.second.assignments()) {
201✔
579
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
62✔
580

581
            std::unordered_set<User*> to_close;
62✔
582
            for (auto& user : open_definitions) {
85✔
583
                if (user.first->container() == entry.first->get_name()) {
23✔
584
                    to_close.insert(user.first);
3✔
585
                }
3✔
586
            }
587
            for (auto& user : to_close) {
65✔
588
                closed_definitions.insert({user, open_definitions.at(user)});
3✔
589
                open_definitions.erase(user);
3✔
590
            }
591
            open_definitions.insert({current_user, {}});
62✔
592
        }
62✔
593
    }
139✔
594
}
97✔
595

596
bool DataDependencyAnalysis::overwrites(User& previous, User& current,
24✔
597
                                        symbolic::Assumptions& assumptions) {
598
    if (previous.use() != Use::WRITE || current.use() != Use::WRITE) {
24✔
NEW
599
        return false;
×
600
    }
601
    if (previous.container() != current.container()) {
24✔
602
        return false;
11✔
603
    }
604
    auto& previous_subsets = previous.subsets();
13✔
605
    auto& current_subsets = current.subsets();
13✔
606

607
    // Check if previous subset is subset of any current subset
608
    for (auto& previous_subset : previous_subsets) {
20✔
609
        bool found = false;
13✔
610
        for (auto& current_subset : current_subsets) {
19✔
611
            if (symbolic::is_subset(previous_subset, current_subset, assumptions)) {
13✔
612
                found = true;
7✔
613
                break;
7✔
614
            }
615
        }
616
        if (!found) {
13✔
617
            return false;
6✔
618
        }
619
    }
620

621
    return true;
7✔
622
}
24✔
623

624
bool DataDependencyAnalysis::reads(User& previous, User& current,
5✔
625
                                   symbolic::Assumptions& assumptions) {
626
    if (previous.use() != Use::WRITE || current.use() != Use::READ) {
5✔
NEW
627
        return false;
×
628
    }
629
    if (previous.container() != current.container()) {
5✔
NEW
630
        return false;
×
631
    }
632
    auto& previous_subsets = previous.subsets();
5✔
633
    auto& current_subsets = current.subsets();
5✔
634

635
    // Check if any current subset intersects with any previous subset
636
    bool found = false;
5✔
637
    for (auto& current_subset : current_subsets) {
6✔
638
        for (auto& previous_subset : previous_subsets) {
6✔
639
            if (!symbolic::is_disjoint(current_subset, previous_subset, assumptions)) {
5✔
640
                found = true;
4✔
641
                break;
4✔
642
            }
643
        }
644
        if (found) {
5✔
645
            break;
4✔
646
        }
647
    }
648

649
    return found;
5✔
650
}
5✔
651

652
/****** Public API ******/
653

NEW
654
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
655
    assert(write.use() == Use::WRITE);
×
656
    if (results_.find(write.container()) == results_.end()) {
×
657
        return {};
×
658
    }
659
    auto& raws = results_.at(write.container());
×
660
    assert(raws.find(&write) != raws.end());
×
661

662
    auto& reads_for_write = raws.at(&write);
×
663

664
    std::unordered_set<User*> reads;
×
665
    for (auto& entry : reads_for_write) {
×
666
        reads.insert(entry);
×
667
    }
668

669
    return reads;
×
670
};
×
671

672
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(
33✔
673
    const std::string& container) {
674
    if (results_.find(container) == results_.end()) {
33✔
675
        return {};
×
676
    }
677
    return results_.at(container);
33✔
678
};
33✔
679

680
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
681
    const std::string& container) {
682
    auto reads = this->definitions(container);
19✔
683

684
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
685
    for (auto& entry : reads) {
43✔
686
        for (auto& read : entry.second) {
51✔
687
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
688
                read_to_writes_map[read] = {};
20✔
689
            }
20✔
690
            read_to_writes_map[read].insert(entry.first);
27✔
691
        }
692
    }
693
    return read_to_writes_map;
19✔
694
};
19✔
695

NEW
696
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
NEW
697
    assert(read.use() == Use::READ);
×
NEW
698
    auto definitions = this->definitions(read.container());
×
699

NEW
700
    std::unordered_set<User*> writes;
×
NEW
701
    for (auto& entry : definitions) {
×
NEW
702
        for (auto& r : entry.second) {
×
NEW
703
            if (&read == r) {
×
NEW
704
                writes.insert(entry.first);
×
NEW
705
            }
×
706
        }
707
    }
NEW
708
    return writes;
×
NEW
709
};
×
710

711
}  // namespace analysis
712
}  // 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