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

daisytuner / sdfglib / 15777530913

20 Jun 2025 11:05AM UTC coverage: 64.569% (-0.02%) from 64.591%
15777530913

Pull #95

github

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

211 of 292 new or added lines in 8 files covered. (72.26%)

22 existing lines in 3 files now uncovered.

8208 of 12712 relevant lines covered (64.57%)

152.59 hits per line

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

76.99
/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
    // Init - Read
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
    // Init - Write
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_definitions) {
12✔
193
            if (overwrites(*user.first, *current_user, assumptions)) {
3✔
194
                to_close.insert(user.first);
2✔
195
            }
2✔
196
        }
197
        for (auto& user : to_close) {
11✔
198
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
199
            open_definitions.erase(user);
2✔
200
        }
201
        open_definitions.insert({current_user, {}});
9✔
202

203
        // Improve: If loop is executed at least once, we can close the init's definition
204
        // TODO: Implement this
205
    }
9✔
206

207
    // Update - Write
208
    {
209
        // Exists after loop and inside body
210
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE,
9✔
211
                                           false, false, true);
212
        open_definitions.insert({current_user, {}});
9✔
213

214
        // Improve: If loop is executed at least once, we can close the init's definition
215
        // TODO: Implement this
216
    }
217

218
    // Condition - Read
219
    for (auto atom : symbolic::atoms(for_loop.condition())) {
19✔
220
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
10✔
221

222
        bool found = false;
10✔
223
        for (auto& user : open_definitions) {
32✔
224
            if (user.first->container() == atom->get_name()) {
22✔
225
                user.second.insert(current_user);
19✔
226
                found = true;
19✔
227
            }
19✔
228
        }
229
        if (!found) {
10✔
NEW
230
            undefined.insert(current_user);
×
231
        }
×
232
    }
10✔
233

234
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
9✔
235
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_for;
9✔
236
    std::unordered_set<User*> undefined_for;
9✔
237

238
    // Add assumptions for body
239
    symbolic::Assumptions body_assumptions = assumptions;
9✔
240
    assumptions_analysis.add(body_assumptions, for_loop.root());
9✔
241
    visit_sequence(users, assumptions_analysis, body_assumptions, for_loop.root(), undefined_for,
9✔
242
                   open_definitions_for, closed_definitions_for);
243

244
    // Update - Read
245
    for (auto atom : symbolic::atoms(for_loop.update())) {
18✔
246
        auto current_user =
9✔
247
            users.get_user(atom->get_name(), &for_loop, Use::READ, false, false, true);
9✔
248

249
        bool found = false;
9✔
250
        for (auto& user : open_definitions_for) {
13✔
251
            if (user.first->container() == atom->get_name()) {
4✔
252
                user.second.insert(current_user);
1✔
253
                found = true;
1✔
254
            }
1✔
255
        }
256
        if (!found) {
9✔
257
            undefined_for.insert(current_user);
8✔
258
        }
8✔
259
    }
9✔
260

261
    // Merge for with outside
262

263
    // Closed definitions are scope-local
264
    for (auto& entry : closed_definitions_for) {
9✔
NEW
265
        closed_definitions.insert(entry);
×
266
    }
267

268
    // Handle open reads of for
269
    for (auto open_read : undefined_for) {
20✔
270
        // Adds artificial loop-carried dependencies
271
        for (auto& user : open_definitions_for) {
17✔
272
            if (user.first->container() == open_read->container()) {
6✔
273
                user.second.insert(open_read);
×
274
            }
×
275
        }
276

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

622
    return true;
9✔
623
}
27✔
624

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

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

650
    return found;
5✔
651
}
5✔
652

653
/****** Public API ******/
654

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

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

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

670
    return reads;
×
671
};
×
672

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

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

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

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

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

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