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

daisytuner / sdfglib / 15843927066

24 Jun 2025 07:17AM UTC coverage: 64.145% (-0.1%) from 64.276%
15843927066

push

github

web-flow
Merge pull request #103 from daisytuner/map-redefinition

adds new map definition into passes

34 of 38 new or added lines in 6 files covered. (89.47%)

2 existing lines in 2 files now uncovered.

8167 of 12732 relevant lines covered (64.15%)

138.22 hits per line

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

86.51
/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)
88✔
19
    : Analysis(sdfg), node_(sdfg.root()) {
88✔
20

21
      };
88✔
22

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

27
      };
×
28

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

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

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

41
    for (auto& entry : open_definitions) {
245✔
42
        closed_definitions.insert(entry);
181✔
43
    }
44

45
    for (auto& entry : closed_definitions) {
252✔
46
        if (results_.find(entry.first->container()) == results_.end()) {
188✔
47
            results_.insert({entry.first->container(), {}});
123✔
48
        }
123✔
49
        results_.at(entry.first->container()).insert(entry);
188✔
50
    }
51
};
64✔
52

53
/****** Visitor API ******/
54

55
void DataDependencyAnalysis::visit_block(
148✔
56
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
57
    structured_control_flow::Block& block, 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();
148✔
61

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

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

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

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

101
                    if (use == Use::READ) {
51✔
102
                        bool found = false;
51✔
103
                        for (auto& user : open_definitions) {
60✔
104
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
9✔
105
                                user.second.insert(current_user);
6✔
106
                                found = true;
6✔
107
                            }
6✔
108
                        }
109
                        if (!found) {
51✔
110
                            undefined.insert(current_user);
46✔
111
                        }
46✔
112
                    }
51✔
113
                }
51✔
114
            }
120✔
115
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
192✔
116
            if (tasklet->is_conditional()) {
72✔
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;
×
122
                        for (auto& user : open_definitions) {
×
123
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
124
                                user.second.insert(current_user);
×
125
                                found = true;
×
126
                            }
×
127
                        }
128
                        if (!found) {
×
129
                            undefined.insert(current_user);
×
130
                        }
×
131
                    }
132
                }
133
            }
×
134
        }
72✔
135

136
        for (auto& oedge : dataflow.out_edges(*node)) {
315✔
137
            std::unordered_set<std::string> used;
123✔
138
            for (auto& dim : oedge.subset()) {
233✔
139
                for (auto atom : symbolic::atoms(dim)) {
195✔
140
                    used.insert(atom->get_name());
85✔
141
                }
85✔
142
            }
143
            for (auto& atom : used) {
208✔
144
                auto current_user = users.get_user(atom, &oedge, Use::READ);
85✔
145

146
                {
147
                    bool found = false;
85✔
148
                    for (auto& user : open_definitions) {
95✔
149
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
10✔
150
                            user.second.insert(current_user);
4✔
151
                            found = true;
4✔
152
                        }
4✔
153
                    }
154
                    if (!found) {
85✔
155
                        undefined.insert(current_user);
81✔
156
                    }
81✔
157
                }
158
            }
159
        }
123✔
160
    }
161
}
148✔
162

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

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

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

190
        std::unordered_set<User*> to_close;
54✔
191
        for (auto& user : open_definitions) {
66✔
192
            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
12✔
193
                to_close.insert(user.first);
2✔
194
            }
2✔
195
        }
196
        for (auto& user : to_close) {
56✔
197
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
198
            open_definitions.erase(user);
2✔
199
        }
200
        open_definitions.insert({current_user, {}});
54✔
201

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

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

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

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

221
        bool found = false;
100✔
222
        for (auto& user : open_definitions) {
311✔
223
            if (user.first->container() == atom->get_name()) {
211✔
224
                user.second.insert(current_user);
109✔
225
                found = true;
109✔
226
            }
109✔
227
        }
228
        if (!found) {
100✔
229
            undefined.insert(current_user);
45✔
230
        }
45✔
231
    }
100✔
232

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

237
    // Add assumptions for body
238
    visit_sequence(users, assumptions_analysis, for_loop.root(), undefined_for,
54✔
239
                   open_definitions_for, closed_definitions_for);
240

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

246
        bool found = false;
54✔
247
        for (auto& user : open_definitions_for) {
129✔
248
            if (user.first->container() == atom->get_name()) {
75✔
249
                user.second.insert(current_user);
1✔
250
                found = true;
1✔
251
            }
1✔
252
        }
253
        if (!found) {
54✔
254
            undefined_for.insert(current_user);
53✔
255
        }
53✔
256
    }
54✔
257

258
    // Merge for with outside
259

260
    // Closed definitions are simply merged
261
    for (auto& entry : closed_definitions_for) {
54✔
262
        closed_definitions.insert(entry);
×
263
    }
264

265
    // Undefined reads are matched or forwarded
266
    for (auto open_read : undefined_for) {
276✔
267
        bool found = false;
222✔
268
        for (auto& entry : open_definitions) {
682✔
269
            if (intersects(*entry.first, *open_read, assumptions_analysis)) {
460✔
270
                entry.second.insert(open_read);
292✔
271
                found = true;
292✔
272
            }
292✔
273
        }
274
        if (!found) {
222✔
275
            undefined.insert(open_read);
76✔
276
        }
76✔
277
    }
278

279
    // Open definitions may close outside open definitions after loop
280
    std::unordered_set<User*> to_close;
54✔
281
    for (auto& previous : open_definitions) {
172✔
282
        for (auto& user : open_definitions_for) {
275✔
283
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
159✔
284
                to_close.insert(previous.first);
2✔
285
                break;
2✔
286
            }
287
        }
288
    }
289
    for (auto& user : to_close) {
56✔
290
        closed_definitions.insert({user, open_definitions.at(user)});
2✔
291
        open_definitions.erase(user);
2✔
292
    }
293

294
    // Add loop-carried dependencies
295

296
    // Criterion 1: Loop is monotonic -> indvar never takes the same value twice
297
    bool is_monotonic = LoopAnalysis::is_monotonic(&for_loop, assumptions_analysis);
54✔
298
    if (is_monotonic) {
54✔
299
        // Case: Can analyze
300
        this->loop_carried_dependencies_.insert({&for_loop, {}});
53✔
301
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
53✔
302

303
        // We can focus on written containers
304

305
        // Case 1: Read-Write between iterations
306
        for (auto& read : undefined_for) {
274✔
307
            for (auto& write : open_definitions_for) {
570✔
308
                if (loop_depends(*write.first, *read, assumptions_analysis, for_loop)) {
349✔
309
                    if (dependencies.find(read->container()) == dependencies.end()) {
7✔
310
                        dependencies.insert(
14✔
311
                            {read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
7✔
312
                    }
7✔
313
                    write.second.insert(read);
7✔
314
                }
7✔
315
            }
316
        }
317

318
        // Case 2: Write-Write between iterations
319
        for (auto& write : open_definitions_for) {
127✔
320
            if (dependencies.find(write.first->container()) != dependencies.end()) {
74✔
321
                continue;
18✔
322
            }
323
            for (auto& write_2 : open_definitions_for) {
127✔
324
                if (loop_depends(*write.first, *write_2.first, assumptions_analysis, for_loop)) {
90✔
325
                    dependencies.insert(
38✔
326
                        {write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
19✔
327
                    break;
19✔
328
                }
329
            }
330
        }
331
    } else {
53✔
332
        // Case: Cannot analyze
333
        this->loop_carried_dependencies_.insert({&for_loop, {}});
1✔
334
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
1✔
335

336
        // Over-Approximation:
337
        // Add loop-carried dependencies for all open reads to all open writes
338
        for (auto& read : undefined_for) {
2✔
339
            for (auto& write : open_definitions_for) {
2✔
340
                if (intersects(*write.first, *read, assumptions_analysis)) {
1✔
341
                    write.second.insert(read);
×
342
                    dependencies.insert({read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
×
343
                }
×
344
            }
345
        }
346
        // Add loop-carried dependencies for writes
347
        for (auto& write : open_definitions_for) {
2✔
348
            if (dependencies.find(write.first->container()) == dependencies.end()) {
1✔
349
                dependencies.insert(
2✔
350
                    {write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
1✔
351
            }
1✔
352
        }
353
    }
354

355
    // Add open definitions from for to outside
356
    for (auto& entry : open_definitions_for) {
129✔
357
        open_definitions.insert(entry);
75✔
358
    }
359
}
54✔
360

361
void DataDependencyAnalysis::visit_if_else(
21✔
362
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
363
    structured_control_flow::IfElse& if_else, std::unordered_set<User*>& undefined,
364
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
365
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
366
    // Read Conditions
367
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
368
        auto child = if_else.at(i).second;
37✔
369
        for (auto atom : symbolic::atoms(child)) {
61✔
370
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
24✔
371

372
            bool found = false;
24✔
373
            for (auto& user : open_definitions) {
38✔
374
                if (user.first->container() == atom->get_name()) {
14✔
375
                    user.second.insert(current_user);
7✔
376
                    found = true;
7✔
377
                }
7✔
378
            }
379
            if (!found) {
24✔
380
                undefined.insert(current_user);
17✔
381
            }
17✔
382
        }
24✔
383
    }
37✔
384

385
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
21✔
386
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(
21✔
387
        if_else.size());
21✔
388
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(
21✔
389
        if_else.size());
21✔
390
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
391
        auto& child = if_else.at(i).first;
37✔
392
        visit_sequence(users, assumptions_analysis, child, undefined_branches.at(i),
74✔
393
                       open_definitions_branches.at(i), closed_definitionss_branches.at(i));
37✔
394
    }
37✔
395

396
    // merge partial open reads
397
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
398
        for (auto& entry : undefined_branches.at(i)) {
41✔
399
            bool found = false;
4✔
400
            for (auto& entry2 : open_definitions) {
8✔
401
                if (entry2.first->container() == entry->container()) {
4✔
402
                    entry2.second.insert(entry);
4✔
403
                    found = true;
4✔
404
                }
4✔
405
            }
406
            if (!found) {
4✔
407
                undefined.insert(entry);
×
408
            }
×
409
        }
410
    }
37✔
411

412
    // merge closed writes
413
    for (auto& closing : closed_definitionss_branches) {
58✔
414
        for (auto& entry : closing) {
37✔
415
            closed_definitions.insert(entry);
×
416
        }
417
    }
418

419
    // Close open reads_after_writes for complete branches
420
    if (if_else.is_complete()) {
21✔
421
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
422
        std::unordered_set<std::string> candidates;
16✔
423
        std::unordered_set<std::string> candidates_tmp;
16✔
424

425
        /* Complete close open reads_after_writes
426
        1. get candidates from first iteration
427
        2. iterate over all branches and prune candidates
428
        3. find prior writes for remaining candidates
429
        4. close open reads_after_writes for all candidates
430
        */
431
        for (auto& entry : open_definitions_branches.at(0)) {
31✔
432
            candidates.insert(entry.first->container());
15✔
433
        }
434
        for (auto& entry : closed_definitionss_branches.at(0)) {
16✔
435
            candidates.insert(entry.first->container());
×
436
        }
437

438
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
439
            for (auto& entry : open_definitions_branches.at(i)) {
30✔
440
                if (candidates.find(entry.first->container()) != candidates.end()) {
14✔
441
                    candidates_tmp.insert(entry.first->container());
14✔
442
                }
14✔
443
            }
444
            candidates.swap(candidates_tmp);
16✔
445
            candidates_tmp.clear();
16✔
446
        }
16✔
447

448
        for (auto& entry : open_definitions) {
24✔
449
            if (candidates.find(entry.first->container()) != candidates.end()) {
8✔
450
                to_close.insert(entry);
4✔
451
            }
4✔
452
        }
453

454
        for (auto& entry : to_close) {
20✔
455
            open_definitions.erase(entry.first);
4✔
456
            closed_definitions.insert(entry);
4✔
457
        }
458
    } else {
16✔
459
        // Over-Approximation: Add all branch definitions to outer definitions or undefined
460
        // Here we add writes to read sets as "anti-reads"
461
        for (auto& branch : open_definitions_branches) {
10✔
462
            for (auto& def : branch) {
8✔
463
                bool found = false;
3✔
464
                for (auto& entry : open_definitions) {
5✔
465
                    if (intersects(*entry.first, *def.first, assumptions_analysis)) {
2✔
466
                        entry.second.insert(def.first);
2✔
467
                        found = true;
2✔
468
                    }
2✔
469
                }
470
                if (!found) {
3✔
471
                    undefined.insert(def.first);
1✔
472
                }
1✔
473
            }
474
        }
475
    }
476

477
    // merge open reads_after_writes
478
    for (auto& branch : open_definitions_branches) {
58✔
479
        for (auto& entry : branch) {
69✔
480
            open_definitions.insert(entry);
32✔
481
        }
482
    }
483
}
21✔
484

485
void DataDependencyAnalysis::visit_while(
7✔
486
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
487
    structured_control_flow::While& while_loop, std::unordered_set<User*>& undefined,
488
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
489
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
490
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
491
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_while;
7✔
492
    std::unordered_set<User*> undefined_while;
7✔
493

494
    visit_sequence(users, assumptions_analysis, while_loop.root(), undefined_while,
7✔
495
                   open_definitions_while, closed_definitions_while);
496

497
    // Scope-local closed definitions
498
    for (auto& entry : closed_definitions_while) {
9✔
499
        closed_definitions.insert(entry);
2✔
500
    }
501

502
    for (auto open_read : undefined_while) {
9✔
503
        // Over-Approximation: Add loop-carried dependencies for all open reads
504
        for (auto& entry : open_definitions_while) {
5✔
505
            if (entry.first->container() == open_read->container()) {
3✔
506
                entry.second.insert(open_read);
2✔
507
            }
2✔
508
        }
509

510
        // Connect to outside
511
        bool found = false;
2✔
512
        for (auto& entry : open_definitions) {
3✔
513
            if (entry.first->container() == open_read->container()) {
1✔
514
                entry.second.insert(open_read);
1✔
515
                found = true;
1✔
516
            }
1✔
517
        }
518
        if (!found) {
2✔
519
            undefined.insert(open_read);
1✔
520
        }
1✔
521
    }
522

523
    // Add open definitions from while to outside
524
    for (auto& entry : open_definitions_while) {
19✔
525
        open_definitions.insert(entry);
12✔
526
    }
527
}
7✔
528

529
void DataDependencyAnalysis::visit_return(
×
530
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
531
    structured_control_flow::Return& return_statement, std::unordered_set<User*>& undefined,
532
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
533
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
534
    // close all open reads_after_writes
535
    for (auto& entry : open_definitions) {
×
536
        closed_definitions.insert(entry);
×
537
    }
538
    open_definitions.clear();
×
539
}
×
540

541
void DataDependencyAnalysis::visit_sequence(
179✔
542
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
543
    structured_control_flow::Sequence& sequence, std::unordered_set<User*>& undefined,
544
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
545
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
546
    for (size_t i = 0; i < sequence.size(); i++) {
409✔
547
        auto child = sequence.at(i);
230✔
548
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
230✔
549
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions,
280✔
550
                        closed_definitions);
140✔
551
        } else if (auto for_loop =
230✔
552
                       dynamic_cast<structured_control_flow::StructuredLoop*>(&child.first)) {
90✔
553
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions,
108✔
554
                      closed_definitions);
54✔
555
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
90✔
556
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions,
42✔
557
                          closed_definitions);
21✔
558
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
36✔
559
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions,
14✔
560
                        closed_definitions);
7✔
561
        } else if (auto return_statement =
15✔
562
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
8✔
563
            visit_return(users, assumptions_analysis, *return_statement, undefined,
×
564
                         open_definitions, closed_definitions);
×
565
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
566
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions,
×
567
                           closed_definitions);
×
UNCOV
568
        }
×
569

570
        // handle transitions read
571
        for (auto& entry : child.second.assignments()) {
299✔
572
            for (auto& atom : symbolic::atoms(entry.second)) {
93✔
573
                if (symbolic::is_pointer(atom)) {
24✔
574
                    continue;
×
575
                }
576
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
24✔
577

578
                bool found = false;
24✔
579
                for (auto& user : open_definitions) {
47✔
580
                    if (user.first->container() == atom->get_name()) {
23✔
581
                        user.second.insert(current_user);
22✔
582
                        found = true;
22✔
583
                    }
22✔
584
                }
585
                if (!found) {
24✔
586
                    undefined.insert(current_user);
10✔
587
                }
10✔
588
            }
589
        }
590

591
        // handle transitions write
592
        for (auto& entry : child.second.assignments()) {
299✔
593
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
69✔
594

595
            std::unordered_set<User*> to_close;
69✔
596
            for (auto& user : open_definitions) {
94✔
597
                if (user.first->container() == entry.first->get_name()) {
25✔
598
                    to_close.insert(user.first);
1✔
599
                }
1✔
600
            }
601
            for (auto& user : to_close) {
70✔
602
                closed_definitions.insert({user, open_definitions.at(user)});
1✔
603
                open_definitions.erase(user);
1✔
604
            }
605
            open_definitions.insert({current_user, {}});
69✔
606
        }
69✔
607
    }
230✔
608
}
179✔
609

610
bool DataDependencyAnalysis::loop_depends(User& previous, User& current,
439✔
611
                                          analysis::AssumptionsAnalysis& assumptions_analysis,
612
                                          structured_control_flow::StructuredLoop& loop) {
613
    if (previous.container() != current.container()) {
439✔
614
        return false;
358✔
615
    }
616
    // Shortcut for scalars
617
    auto& type = this->sdfg_.type(previous.container());
81✔
618
    if (dynamic_cast<const types::Scalar*>(&type)) {
81✔
619
        return true;
18✔
620
    }
621

622
    auto& previous_subsets = previous.subsets();
63✔
623
    auto& current_subsets = current.subsets();
63✔
624

625
    auto previous_scope = Users::scope(&previous);
63✔
626
    auto previous_assumptions = assumptions_analysis.get(loop.root(), *previous_scope, true);
63✔
627
    auto current_scope = Users::scope(&current);
63✔
628
    auto current_assumptions = assumptions_analysis.get(loop.root(), *current_scope, true);
63✔
629

630
    // Check if previous subset is subset of any current subset
631
    for (auto& previous_subset : previous_subsets) {
118✔
632
        for (auto& current_subset : current_subsets) {
118✔
633
            if (symbolic::maps::intersects(previous_subset, current_subset, loop.indvar(),
63✔
634
                                           previous_assumptions, current_assumptions)) {
635
                return true;
8✔
636
            }
637
        }
638
    }
639

640
    return false;
55✔
641
}
439✔
642

643
bool DataDependencyAnalysis::supersedes(User& previous, User& current,
195✔
644
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
645
    if (previous.container() != current.container()) {
195✔
646
        return false;
179✔
647
    }
648
    // Shortcut for scalars
649
    auto& type = this->sdfg_.type(previous.container());
16✔
650
    if (dynamic_cast<const types::Scalar*>(&type)) {
16✔
651
        return true;
3✔
652
    }
653

654
    auto& previous_subsets = previous.subsets();
13✔
655
    auto& current_subsets = current.subsets();
13✔
656
    auto previous_scope = Users::scope(&previous);
13✔
657
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
13✔
658
    auto current_scope = Users::scope(&current);
13✔
659
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
13✔
660

661
    // Check if previous subset is subset of any current subset
662
    for (auto& previous_subset : previous_subsets) {
21✔
663
        bool found = false;
13✔
664
        for (auto& current_subset : current_subsets) {
18✔
665
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions,
13✔
666
                                    current_assumptions)) {
667
                found = true;
8✔
668
                break;
8✔
669
            }
670
        }
671
        if (!found) {
13✔
672
            return false;
5✔
673
        }
674
    }
675

676
    return true;
8✔
677
}
195✔
678

679
bool DataDependencyAnalysis::intersects(User& previous, User& current,
482✔
680
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
681
    if (previous.container() != current.container()) {
482✔
682
        return false;
177✔
683
    }
684
    // Shortcut for scalars
685
    auto& type = this->sdfg_.type(previous.container());
305✔
686
    if (dynamic_cast<const types::Scalar*>(&type)) {
305✔
687
        return true;
303✔
688
    }
689

690
    auto& previous_subsets = previous.subsets();
2✔
691
    auto& current_subsets = current.subsets();
2✔
692

693
    auto previous_scope = Users::scope(&previous);
2✔
694
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
2✔
695
    auto current_scope = Users::scope(&current);
2✔
696
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
2✔
697

698
    // Check if any current subset intersects with any previous subset
699
    bool found = false;
2✔
700
    for (auto& current_subset : current_subsets) {
3✔
701
        for (auto& previous_subset : previous_subsets) {
3✔
702
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions,
2✔
703
                                       previous_assumptions)) {
704
                found = true;
1✔
705
                break;
1✔
706
            }
707
        }
708
        if (found) {
2✔
709
            break;
1✔
710
        }
711
    }
712

713
    return found;
2✔
714
}
482✔
715

716
/****** Public API ******/
717

718
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
719
    assert(write.use() == Use::WRITE);
×
720
    if (results_.find(write.container()) == results_.end()) {
×
721
        return {};
×
722
    }
723
    auto& raws = results_.at(write.container());
×
724
    assert(raws.find(&write) != raws.end());
×
725

726
    auto& reads_for_write = raws.at(&write);
×
727

728
    std::unordered_set<User*> reads;
×
729
    for (auto& entry : reads_for_write) {
×
730
        reads.insert(entry);
×
731
    }
732

733
    return reads;
×
734
};
×
735

736
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(
33✔
737
    const std::string& container) {
738
    if (results_.find(container) == results_.end()) {
33✔
739
        return {};
×
740
    }
741
    return results_.at(container);
33✔
742
};
33✔
743

744
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
745
    const std::string& container) {
746
    auto reads = this->definitions(container);
19✔
747

748
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
749
    for (auto& entry : reads) {
43✔
750
        for (auto& read : entry.second) {
51✔
751
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
752
                read_to_writes_map[read] = {};
20✔
753
            }
20✔
754
            read_to_writes_map[read].insert(entry.first);
27✔
755
        }
756
    }
757
    return read_to_writes_map;
19✔
758
};
19✔
759

760
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
761
    assert(read.use() == Use::READ);
×
762
    auto definitions = this->definitions(read.container());
×
763

764
    std::unordered_set<User*> writes;
×
765
    for (auto& entry : definitions) {
×
766
        for (auto& r : entry.second) {
×
767
            if (&read == r) {
×
768
                writes.insert(entry.first);
×
769
            }
×
770
        }
771
    }
772
    return writes;
×
773
};
×
774

775
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
776
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
777
};
778

779
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::dependencies(
39✔
780
    structured_control_flow::StructuredLoop& loop) const {
781
    return this->loop_carried_dependencies_.at(&loop);
39✔
782
};
783

784
}  // namespace analysis
785
}  // 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