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

daisytuner / sdfglib / 18651924023

20 Oct 2025 12:26PM UTC coverage: 60.977% (-0.6%) from 61.539%
18651924023

push

github

web-flow
Merge pull request #286 from daisytuner/reserved-names

removes restricted globals filtering in codegen

8 of 20 new or added lines in 2 files covered. (40.0%)

342 existing lines in 17 files now uncovered.

9174 of 15045 relevant lines covered (60.98%)

92.1 hits per line

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

84.41
/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/analysis/loop_analysis.h"
11
#include "sdfg/structured_sdfg.h"
12
#include "sdfg/symbolic/maps.h"
13
#include "sdfg/symbolic/sets.h"
14

15
namespace sdfg {
16
namespace analysis {
17

18
DataDependencyAnalysis::DataDependencyAnalysis(StructuredSDFG& sdfg)
95✔
19
    : Analysis(sdfg), node_(sdfg.root()) {
95✔
20

21
      };
95✔
22

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

26
      };
×
27

28
void DataDependencyAnalysis::run(analysis::AnalysisManager& analysis_manager) {
71✔
29
    results_.clear();
71✔
30
    loop_carried_dependencies_.clear();
71✔
31

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

36
    auto& assumptions_analysis = analysis_manager.get<AssumptionsAnalysis>();
71✔
37
    auto& users = analysis_manager.get<Users>();
71✔
38
    visit_sequence(users, assumptions_analysis, node_, undefined, open_definitions, closed_definitions);
71✔
39

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

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

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

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

64
    for (auto node : dataflow.topological_sort()) {
399✔
65
        if (dynamic_cast<data_flow::ConstantNode*>(node) != nullptr) {
236✔
66
            continue;
12✔
67
        }
68

69
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
224✔
70
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
141✔
71
                if (dataflow.in_degree(*node) > 0) {
141✔
72
                    Use use = Use::WRITE;
83✔
73
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
166✔
74
                        if (iedge.type() == data_flow::MemletType::Reference ||
166✔
75
                            iedge.type() == data_flow::MemletType::Dereference_Src) {
83✔
76
                            use = Use::MOVE;
×
77
                            break;
×
78
                        }
79
                    }
80

81
                    auto current_user = users.get_user(access_node->data(), access_node, use);
83✔
82

83
                    if (use == Use::WRITE) {
83✔
84
                        // Close all definitions that we supersede
85
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
83✔
86
                        for (auto& user : open_definitions) {
119✔
87
                            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
36✔
88
                                to_close.insert(user);
8✔
89
                            }
8✔
90
                        }
91
                        for (auto& user : to_close) {
91✔
92
                            open_definitions.erase(user.first);
8✔
93
                            closed_definitions.insert(user);
8✔
94
                        }
95

96
                        // Add new definition
97
                        open_definitions.insert({current_user, {}});
83✔
98
                    }
83✔
99
                }
83✔
100
                if (dataflow.out_degree(*access_node) > 0) {
141✔
101
                    Use use = Use::READ;
61✔
102
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
123✔
103
                        if (oedge.type() == data_flow::MemletType::Reference ||
124✔
104
                            oedge.type() == data_flow::MemletType::Dereference_Dst) {
62✔
105
                            use = Use::VIEW;
×
106
                            break;
×
107
                        }
108
                    }
109

110
                    auto current_user = users.get_user(access_node->data(), access_node, use);
61✔
111

112
                    if (use == Use::READ) {
61✔
113
                        // Find all definitions that we read from
114
                        bool found = false;
61✔
115
                        for (auto& user : open_definitions) {
90✔
116
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
29✔
117
                                user.second.insert(current_user);
9✔
118
                                found = true;
9✔
119
                            }
9✔
120
                        }
121
                        if (!found) {
61✔
122
                            undefined.insert(current_user);
53✔
123
                        } else {
53✔
124
                            bool supersedes_all = true;
8✔
125
                            for (auto& user : open_definitions) {
20✔
126
                                if (user.first->container() == current_user->container()) {
12✔
127
                                    supersedes_all &= supersedes(*user.first, *current_user, assumptions_analysis);
9✔
128
                                }
9✔
129
                            }
130
                            if (!supersedes_all) {
8✔
131
                                undefined.insert(current_user);
×
132
                            }
×
133
                        }
134
                    }
61✔
135
                }
61✔
136
            }
141✔
137
        } else if (auto library_node = dynamic_cast<data_flow::LibraryNode*>(node)) {
224✔
138
            for (auto& symbol : library_node->symbols()) {
×
139
                auto current_user = users.get_user(symbol->get_name(), library_node, Use::READ);
×
140
                {
141
                    // Find all definitions that we read from
142
                    bool found = false;
×
143
                    bool superseded_all = false;
×
144
                    for (auto& user : open_definitions) {
×
145
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
146
                            user.second.insert(current_user);
×
147
                            if (!found) {
×
148
                                found = true;
×
149
                                superseded_all = true;
×
150
                            }
×
151
                            superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
×
152
                        }
×
153
                    }
154
                    if (!superseded_all) {
×
155
                        undefined.insert(current_user);
×
156
                    }
×
157
                }
158
            }
159
        }
×
160

161
        for (auto& oedge : dataflow.out_edges(*node)) {
369✔
162
            std::unordered_set<std::string> used;
145✔
163
            for (auto& dim : oedge.subset()) {
276✔
164
                for (auto atom : symbolic::atoms(dim)) {
268✔
165
                    used.insert(atom->get_name());
137✔
166
                }
137✔
167
            }
168
            for (auto& atom : used) {
282✔
169
                auto current_user = users.get_user(atom, &oedge, Use::READ);
137✔
170

171
                {
172
                    // Find all definitions that we read from
173
                    bool found = false;
137✔
174
                    bool superseded_all = false;
137✔
175
                    for (auto& user : open_definitions) {
221✔
176
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
84✔
177
                            user.second.insert(current_user);
4✔
178
                            if (!found) {
4✔
179
                                found = true;
4✔
180
                                superseded_all = true;
4✔
181
                            }
4✔
182
                            superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
4✔
183
                        }
4✔
184
                    }
185
                    if (!superseded_all) {
137✔
186
                        undefined.insert(current_user);
133✔
187
                    }
133✔
188
                }
189
            }
190
        }
145✔
191
    }
192
}
163✔
193

194
void DataDependencyAnalysis::visit_for(
65✔
195
    analysis::Users& users,
196
    analysis::AssumptionsAnalysis& assumptions_analysis,
197
    structured_control_flow::StructuredLoop& for_loop,
198
    std::unordered_set<User*>& undefined,
199
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
200
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
201
) {
202
    // Init - Read
203
    for (auto atom : symbolic::atoms(for_loop.init())) {
73✔
204
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
8✔
205

206
        bool found = false;
8✔
207
        for (auto& user : open_definitions) {
16✔
208
            if (user.first->container() == atom->get_name()) {
8✔
209
                user.second.insert(current_user);
1✔
210
                found = true;
1✔
211
            }
1✔
212
        }
213
        if (!found) {
8✔
214
            undefined.insert(current_user);
7✔
215
        }
7✔
216
    }
8✔
217

218
    // Init - Write
219
    {
220
        // Write Induction Variable
221
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, true);
65✔
222

223
        std::unordered_set<User*> to_close;
65✔
224
        for (auto& user : open_definitions) {
85✔
225
            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
20✔
226
                to_close.insert(user.first);
2✔
227
            }
2✔
228
        }
229
        for (auto& user : to_close) {
67✔
230
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
231
            open_definitions.erase(user);
2✔
232
        }
233
        open_definitions.insert({current_user, {}});
65✔
234

235
        // Improve: If loop is executed at least once, we can close the init's definition
236
        // TODO: Implement this
237
    }
65✔
238

239
    // Update - Write
240
    {
241
        // Exists after loop and inside body
242
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, false, false, true);
65✔
243
        open_definitions.insert({current_user, {}});
65✔
244

245
        // Improve: If loop is executed at least once, we can close the init's definition
246
        // TODO: Implement this
247
    }
248

249
    // Condition - Read
250
    for (auto atom : symbolic::atoms(for_loop.condition())) {
184✔
251
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
119✔
252

253
        bool found = false;
119✔
254
        for (auto& user : open_definitions) {
377✔
255
            if (user.first->container() == atom->get_name()) {
258✔
256
                user.second.insert(current_user);
131✔
257
                found = true;
131✔
258
            }
131✔
259
        }
260
        if (!found) {
119✔
261
            undefined.insert(current_user);
53✔
262
        }
53✔
263
    }
119✔
264

265
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
65✔
266
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_for;
65✔
267
    std::unordered_set<User*> undefined_for;
65✔
268

269
    // Add assumptions for body
270
    visit_sequence(
65✔
271
        users, assumptions_analysis, for_loop.root(), undefined_for, open_definitions_for, closed_definitions_for
65✔
272
    );
273

274
    // Update - Read
275
    for (auto atom : symbolic::atoms(for_loop.update())) {
130✔
276
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, false, true);
65✔
277

278
        bool found = false;
65✔
279
        for (auto& user : open_definitions_for) {
188✔
280
            if (user.first->container() == atom->get_name()) {
123✔
281
                user.second.insert(current_user);
1✔
282
                found = true;
1✔
283
            }
1✔
284
        }
285
        if (!found) {
65✔
286
            undefined_for.insert(current_user);
64✔
287
        }
64✔
288
    }
65✔
289

290
    // Merge for with outside
291

292
    // Closed definitions are simply merged
293
    for (auto& entry : closed_definitions_for) {
68✔
294
        closed_definitions.insert(entry);
3✔
295
    }
296

297
    // Undefined reads are matched or forwarded
298
    for (auto open_read : undefined_for) {
462✔
299
        bool found = false;
397✔
300
        for (auto& entry : open_definitions) {
1,408✔
301
            if (intersects(*entry.first, *open_read, assumptions_analysis)) {
1,011✔
302
                entry.second.insert(open_read);
398✔
303
                found = true;
398✔
304
            }
398✔
305
        }
306
        if (!found) {
397✔
307
            undefined.insert(open_read);
197✔
308
        } else {
197✔
309
            bool subset_all = true;
200✔
310
            for (auto& entry : open_definitions) {
668✔
311
                if (entry.first->container() == open_read->container()) {
468✔
312
                    subset_all &= supersedes_restrictive(*open_read, *entry.first, assumptions_analysis);
398✔
313
                }
398✔
314
            }
315
            if (!subset_all) {
200✔
316
                undefined.insert(open_read);
1✔
317
            }
1✔
318
        }
319
    }
320

321
    // Open definitions may close outside open definitions after loop
322
    std::unordered_set<User*> to_close;
65✔
323
    for (auto& previous : open_definitions) {
213✔
324
        for (auto& user : open_definitions_for) {
430✔
325
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
284✔
326
                to_close.insert(previous.first);
2✔
327
                break;
2✔
328
            }
329
        }
330
    }
331
    for (auto& user : to_close) {
67✔
332
        closed_definitions.insert({user, open_definitions.at(user)});
2✔
333
        open_definitions.erase(user);
2✔
334
    }
335

336
    // Add loop-carried dependencies
337

338
    // Criterion 1: Loop is monotonic -> indvar never takes the same value twice
339
    bool is_monotonic = LoopAnalysis::is_monotonic(&for_loop, assumptions_analysis);
65✔
340
    if (is_monotonic) {
65✔
341
        // Case: Can analyze
342
        bool success = this->loop_carried_dependencies_.insert({&for_loop, {}}).second;
64✔
343
        assert(success);
64✔
344
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
64✔
345

346
        // We can focus on written containers
347

348
        // Case 1: Read-Write between iterations
349
        for (auto& read : undefined_for) {
460✔
350
            for (auto& write : open_definitions_for) {
2,052✔
351
                if (loop_depends(*write.first, *read, assumptions_analysis, for_loop)) {
1,656✔
352
                    dependencies[read->container()] = LOOP_CARRIED_DEPENDENCY_READ_WRITE;
39✔
353
                    write.second.insert(read);
39✔
354
                }
39✔
355
            }
356
        }
357

358
        // Case 2: Write-Write between iterations
359
        for (auto& write : open_definitions_for) {
186✔
360
            if (dependencies.find(write.first->container()) != dependencies.end()) {
122✔
361
                continue;
38✔
362
            }
363
            for (auto& write_2 : open_definitions_for) {
245✔
364
                if (loop_depends(*write.first, *write_2.first, assumptions_analysis, for_loop)) {
203✔
365
                    dependencies.insert({write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
42✔
366
                    break;
42✔
367
                }
368
            }
369
        }
370
    } else {
64✔
371
        // Case: Cannot analyze
372
        bool success = this->loop_carried_dependencies_.insert({&for_loop, {}}).second;
1✔
373
        assert(success);
1✔
374
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
1✔
375

376
        // Over-Approximation:
377
        // Add loop-carried dependencies for all open reads to all open writes
378
        for (auto& read : undefined_for) {
2✔
379
            for (auto& write : open_definitions_for) {
2✔
380
                if (intersects(*write.first, *read, assumptions_analysis)) {
1✔
381
                    write.second.insert(read);
×
382
                    dependencies.insert({read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
×
383
                }
×
384
            }
385
        }
386
        // Add loop-carried dependencies for writes
387
        for (auto& write : open_definitions_for) {
2✔
388
            if (dependencies.find(write.first->container()) == dependencies.end()) {
1✔
389
                dependencies.insert({write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
1✔
390
            }
1✔
391
        }
392
    }
393

394
    // Add open definitions from for to outside
395
    for (auto& entry : open_definitions_for) {
188✔
396
        open_definitions.insert(entry);
123✔
397
    }
398
}
65✔
399

400
void DataDependencyAnalysis::visit_if_else(
21✔
401
    analysis::Users& users,
402
    analysis::AssumptionsAnalysis& assumptions_analysis,
403
    structured_control_flow::IfElse& if_else,
404
    std::unordered_set<User*>& undefined,
405
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
406
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
407
) {
408
    // Read Conditions
409
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
410
        auto child = if_else.at(i).second;
37✔
411
        for (auto atom : symbolic::atoms(child)) {
61✔
412
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
24✔
413

414
            bool found = false;
24✔
415
            for (auto& user : open_definitions) {
38✔
416
                if (user.first->container() == atom->get_name()) {
14✔
417
                    user.second.insert(current_user);
7✔
418
                    found = true;
7✔
419
                }
7✔
420
            }
421
            if (!found) {
24✔
422
                undefined.insert(current_user);
17✔
423
            }
17✔
424
        }
24✔
425
    }
37✔
426

427
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
21✔
428
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(if_else.size());
21✔
429
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(if_else.size());
21✔
430
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
431
        auto& child = if_else.at(i).first;
37✔
432
        visit_sequence(
37✔
433
            users,
37✔
434
            assumptions_analysis,
37✔
435
            child,
37✔
436
            undefined_branches.at(i),
37✔
437
            open_definitions_branches.at(i),
37✔
438
            closed_definitionss_branches.at(i)
37✔
439
        );
440
    }
37✔
441

442
    // merge partial open reads
443
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
444
        for (auto& entry : undefined_branches.at(i)) {
41✔
445
            bool found = false;
4✔
446
            for (auto& entry2 : open_definitions) {
8✔
447
                if (entry2.first->container() == entry->container()) {
4✔
448
                    entry2.second.insert(entry);
4✔
449
                    found = true;
4✔
450
                }
4✔
451
            }
452
            if (!found) {
4✔
453
                undefined.insert(entry);
×
454
            }
×
455
        }
456
    }
37✔
457

458
    // merge closed writes
459
    for (auto& closing : closed_definitionss_branches) {
58✔
460
        for (auto& entry : closing) {
37✔
461
            closed_definitions.insert(entry);
×
462
        }
463
    }
464

465
    // Close open reads_after_writes for complete branches
466
    if (if_else.is_complete()) {
21✔
467
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
468
        std::unordered_set<std::string> candidates;
16✔
469
        std::unordered_set<std::string> candidates_tmp;
16✔
470

471
        /* Complete close open reads_after_writes
472
        1. get candidates from first iteration
473
        2. iterate over all branches and prune candidates
474
        3. find prior writes for remaining candidates
475
        4. close open reads_after_writes for all candidates
476
        */
477
        for (auto& entry : open_definitions_branches.at(0)) {
31✔
478
            candidates.insert(entry.first->container());
15✔
479
        }
480
        for (auto& entry : closed_definitionss_branches.at(0)) {
16✔
481
            candidates.insert(entry.first->container());
×
482
        }
483

484
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
485
            for (auto& entry : open_definitions_branches.at(i)) {
30✔
486
                if (candidates.find(entry.first->container()) != candidates.end()) {
14✔
487
                    candidates_tmp.insert(entry.first->container());
14✔
488
                }
14✔
489
            }
490
            candidates.swap(candidates_tmp);
16✔
491
            candidates_tmp.clear();
16✔
492
        }
16✔
493

494
        for (auto& entry : open_definitions) {
24✔
495
            if (candidates.find(entry.first->container()) != candidates.end()) {
8✔
496
                to_close.insert(entry);
4✔
497
            }
4✔
498
        }
499

500
        for (auto& entry : to_close) {
20✔
501
            open_definitions.erase(entry.first);
4✔
502
            closed_definitions.insert(entry);
4✔
503
        }
504
    }
16✔
505

506
    // merge open reads_after_writes
507
    for (auto& branch : open_definitions_branches) {
58✔
508
        for (auto& entry : branch) {
69✔
509
            open_definitions.insert(entry);
32✔
510
        }
511
    }
512
}
21✔
513

514
void DataDependencyAnalysis::visit_while(
7✔
515
    analysis::Users& users,
516
    analysis::AssumptionsAnalysis& assumptions_analysis,
517
    structured_control_flow::While& while_loop,
518
    std::unordered_set<User*>& undefined,
519
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
520
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
521
) {
522
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
523
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_while;
7✔
524
    std::unordered_set<User*> undefined_while;
7✔
525

526
    visit_sequence(
7✔
527
        users, assumptions_analysis, while_loop.root(), undefined_while, open_definitions_while, closed_definitions_while
7✔
528
    );
529

530
    // Scope-local closed definitions
531
    for (auto& entry : closed_definitions_while) {
9✔
532
        closed_definitions.insert(entry);
2✔
533
    }
534

535
    for (auto open_read : undefined_while) {
9✔
536
        // Over-Approximation: Add loop-carried dependencies for all open reads
537
        for (auto& entry : open_definitions_while) {
5✔
538
            if (entry.first->container() == open_read->container()) {
3✔
539
                entry.second.insert(open_read);
2✔
540
            }
2✔
541
        }
542

543
        // Connect to outside
544
        bool found = false;
2✔
545
        for (auto& entry : open_definitions) {
3✔
546
            if (entry.first->container() == open_read->container()) {
1✔
547
                entry.second.insert(open_read);
1✔
548
                found = true;
1✔
549
            }
1✔
550
        }
551
        if (!found) {
2✔
552
            undefined.insert(open_read);
1✔
553
        }
1✔
554
    }
555

556
    // Add open definitions from while to outside
557
    for (auto& entry : open_definitions_while) {
19✔
558
        open_definitions.insert(entry);
12✔
559
    }
560
}
7✔
561

UNCOV
562
void DataDependencyAnalysis::visit_return(
×
563
    analysis::Users& users,
564
    analysis::AssumptionsAnalysis& assumptions_analysis,
565
    structured_control_flow::Return& return_statement,
566
    std::unordered_set<User*>& undefined,
567
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
568
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
569
) {
UNCOV
570
    if (return_statement.is_data() && !return_statement.data().empty()) {
×
UNCOV
571
        auto current_user = users.get_user(return_statement.data(), &return_statement, Use::READ);
×
572

UNCOV
573
        bool found = false;
×
UNCOV
574
        for (auto& user : open_definitions) {
×
UNCOV
575
            if (user.first->container() == return_statement.data()) {
×
UNCOV
576
                user.second.insert(current_user);
×
UNCOV
577
                found = true;
×
UNCOV
578
            }
×
579
        }
UNCOV
580
        if (!found) {
×
UNCOV
581
            undefined.insert(current_user);
×
UNCOV
582
        }
×
UNCOV
583
    }
×
584

585
    // close all open reads_after_writes
UNCOV
586
    for (auto& entry : open_definitions) {
×
587
        closed_definitions.insert(entry);
×
588
    }
UNCOV
589
    open_definitions.clear();
×
590
}
×
591

592
void DataDependencyAnalysis::visit_sequence(
197✔
593
    analysis::Users& users,
594
    analysis::AssumptionsAnalysis& assumptions_analysis,
595
    structured_control_flow::Sequence& sequence,
596
    std::unordered_set<User*>& undefined,
597
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
598
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
599
) {
600
    for (size_t i = 0; i < sequence.size(); i++) {
453✔
601
        auto child = sequence.at(i);
256✔
602
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
256✔
603
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions, closed_definitions);
155✔
604
        } else if (auto for_loop = dynamic_cast<structured_control_flow::StructuredLoop*>(&child.first)) {
256✔
605
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions, closed_definitions);
65✔
606
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
101✔
607
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions, closed_definitions);
21✔
608
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
36✔
609
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions, closed_definitions);
7✔
610
        } else if (auto return_statement = dynamic_cast<structured_control_flow::Return*>(&child.first)) {
15✔
UNCOV
611
            visit_return(users, assumptions_analysis, *return_statement, undefined, open_definitions, closed_definitions);
×
612
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
UNCOV
613
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions, closed_definitions);
×
UNCOV
614
        }
×
615

616
        // handle transitions read
617
        for (auto& entry : child.second.assignments()) {
329✔
618
            for (auto& atom : symbolic::atoms(entry.second)) {
103✔
619
                if (symbolic::is_pointer(atom)) {
30✔
620
                    continue;
2✔
621
                }
622
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
28✔
623

624
                bool found = false;
28✔
625
                for (auto& user : open_definitions) {
53✔
626
                    if (user.first->container() == atom->get_name()) {
25✔
627
                        user.second.insert(current_user);
22✔
628
                        found = true;
22✔
629
                    }
22✔
630
                }
631
                if (!found) {
28✔
632
                    undefined.insert(current_user);
14✔
633
                }
14✔
634
            }
635
        }
636

637
        // handle transitions write
638
        for (auto& entry : child.second.assignments()) {
329✔
639
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
73✔
640

641
            std::unordered_set<User*> to_close;
73✔
642
            for (auto& user : open_definitions) {
100✔
643
                if (user.first->container() == entry.first->get_name()) {
27✔
644
                    to_close.insert(user.first);
3✔
645
                }
3✔
646
            }
647
            for (auto& user : to_close) {
76✔
648
                closed_definitions.insert({user, open_definitions.at(user)});
3✔
649
                open_definitions.erase(user);
3✔
650
            }
651
            open_definitions.insert({current_user, {}});
73✔
652
        }
73✔
653
    }
256✔
654
}
197✔
655

656
bool DataDependencyAnalysis::loop_depends(
1,859✔
657
    User& previous,
658
    User& current,
659
    analysis::AssumptionsAnalysis& assumptions_analysis,
660
    structured_control_flow::StructuredLoop& loop
661
) {
662
    if (previous.container() != current.container()) {
1,859✔
663
        return false;
1,705✔
664
    }
665
    // Shortcut for scalars
666
    auto& type = this->sdfg_.type(previous.container());
154✔
667
    if (dynamic_cast<const types::Scalar*>(&type)) {
154✔
668
        return true;
40✔
669
    }
670

671
    auto& previous_subsets = previous.subsets();
114✔
672
    auto& current_subsets = current.subsets();
114✔
673

674
    auto previous_scope = Users::scope(&previous);
114✔
675
    auto previous_assumptions = assumptions_analysis.get(loop.root(), *previous_scope, true);
114✔
676
    auto current_scope = Users::scope(&current);
114✔
677
    auto current_assumptions = assumptions_analysis.get(loop.root(), *current_scope, true);
114✔
678

679
    // Check if previous subset is subset of any current subset
680
    for (auto& previous_subset : previous_subsets) {
187✔
681
        for (auto& current_subset : current_subsets) {
188✔
682
            if (symbolic::maps::intersects(
115✔
683
                    previous_subset, current_subset, loop.indvar(), previous_assumptions, current_assumptions
115✔
684
                )) {
685
                return true;
41✔
686
            }
687
        }
688
    }
689

690
    return false;
73✔
691
}
1,859✔
692

693
bool DataDependencyAnalysis::supersedes(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
353✔
694
    if (previous.container() != current.container()) {
353✔
695
        return false;
321✔
696
    }
697
    // Shortcut for scalars
698
    auto& type = this->sdfg_.type(previous.container());
32✔
699
    if (dynamic_cast<const types::Scalar*>(&type)) {
32✔
700
        return true;
14✔
701
    }
702

703
    auto& previous_subsets = previous.subsets();
18✔
704
    auto& current_subsets = current.subsets();
18✔
705
    auto previous_scope = Users::scope(&previous);
18✔
706
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
18✔
707
    auto current_scope = Users::scope(&current);
18✔
708
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
18✔
709

710
    // Check if previous subset is subset of any current subset
711
    for (auto& previous_subset : previous_subsets) {
29✔
712
        bool found = false;
18✔
713
        for (auto& current_subset : current_subsets) {
25✔
714
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions, current_assumptions)) {
18✔
715
                found = true;
11✔
716
                break;
11✔
717
            }
718
        }
719
        if (!found) {
18✔
720
            return false;
7✔
721
        }
722
    }
723

724
    return true;
11✔
725
}
353✔
726

727
bool DataDependencyAnalysis::
728
    supersedes_restrictive(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
398✔
729
    if (previous.container() != current.container()) {
398✔
UNCOV
730
        return false;
×
731
    }
732
    // Shortcut for scalars
733
    auto& type = this->sdfg_.type(previous.container());
398✔
734
    if (dynamic_cast<const types::Scalar*>(&type)) {
398✔
735
        return true;
397✔
736
    }
737

738
    auto& previous_subsets = previous.subsets();
1✔
739
    auto& current_subsets = current.subsets();
1✔
740
    auto previous_scope = Users::scope(&previous);
1✔
741
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
1✔
742
    auto current_scope = Users::scope(&current);
1✔
743
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
1✔
744

745
    // Check if previous subset is subset of any current subset
746
    for (auto& previous_subset : previous_subsets) {
1✔
747
        bool found = false;
1✔
748
        for (auto& current_subset : current_subsets) {
2✔
749
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions, previous_assumptions)) {
1✔
UNCOV
750
                found = true;
×
UNCOV
751
                break;
×
752
            }
753
        }
754
        if (!found) {
1✔
755
            return false;
1✔
756
        }
757
    }
758

UNCOV
759
    return true;
×
760
}
398✔
761

762
bool DataDependencyAnalysis::intersects(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
1,125✔
763
    if (previous.container() != current.container()) {
1,125✔
764
        return false;
709✔
765
    }
766
    // Shortcut for scalars
767
    auto& type = this->sdfg_.type(previous.container());
416✔
768
    if (dynamic_cast<const types::Scalar*>(&type)) {
416✔
769
        return true;
408✔
770
    }
771

772
    auto& previous_subsets = previous.subsets();
8✔
773
    auto& current_subsets = current.subsets();
8✔
774

775
    auto previous_scope = Users::scope(&previous);
8✔
776
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
8✔
777
    auto current_scope = Users::scope(&current);
8✔
778
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
8✔
779

780
    // Check if any current subset intersects with any previous subset
781
    bool found = false;
8✔
782
    for (auto& current_subset : current_subsets) {
13✔
783
        for (auto& previous_subset : previous_subsets) {
13✔
784
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions, previous_assumptions)) {
8✔
785
                found = true;
3✔
786
                break;
3✔
787
            }
788
        }
789
        if (found) {
8✔
790
            break;
3✔
791
        }
792
    }
793

794
    return found;
8✔
795
}
1,125✔
796

797
/****** Public API ******/
798

UNCOV
799
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
UNCOV
800
    assert(write.use() == Use::WRITE);
×
UNCOV
801
    if (results_.find(write.container()) == results_.end()) {
×
UNCOV
802
        return {};
×
803
    }
UNCOV
804
    auto& raws = results_.at(write.container());
×
UNCOV
805
    assert(raws.find(&write) != raws.end());
×
806

UNCOV
807
    auto& reads_for_write = raws.at(&write);
×
808

UNCOV
809
    std::unordered_set<User*> reads;
×
UNCOV
810
    for (auto& entry : reads_for_write) {
×
UNCOV
811
        reads.insert(entry);
×
812
    }
813

UNCOV
814
    return reads;
×
UNCOV
815
};
×
816

817
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(const std::string& container) {
37✔
818
    if (results_.find(container) == results_.end()) {
37✔
819
        return {};
2✔
820
    }
821
    return results_.at(container);
35✔
822
};
37✔
823

824
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(const std::string& container) {
19✔
825
    auto reads = this->definitions(container);
19✔
826

827
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
828
    for (auto& entry : reads) {
43✔
829
        for (auto& read : entry.second) {
51✔
830
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
831
                read_to_writes_map[read] = {};
20✔
832
            }
20✔
833
            read_to_writes_map[read].insert(entry.first);
27✔
834
        }
835
    }
836
    return read_to_writes_map;
19✔
837
};
19✔
838

UNCOV
839
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
UNCOV
840
    assert(read.use() == Use::READ);
×
UNCOV
841
    auto definitions = this->definitions(read.container());
×
842

UNCOV
843
    std::unordered_set<User*> writes;
×
UNCOV
844
    for (auto& entry : definitions) {
×
UNCOV
845
        for (auto& r : entry.second) {
×
UNCOV
846
            if (&read == r) {
×
UNCOV
847
                writes.insert(entry.first);
×
UNCOV
848
            }
×
849
        }
850
    }
UNCOV
851
    return writes;
×
UNCOV
852
};
×
853

UNCOV
854
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
UNCOV
855
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
856
};
857

858
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::
859
    dependencies(structured_control_flow::StructuredLoop& loop) const {
50✔
860
    return this->loop_carried_dependencies_.at(&loop);
50✔
861
};
862

863
} // namespace analysis
864
} // 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