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

daisytuner / sdfglib / 16829038698

08 Aug 2025 11:15AM UTC coverage: 64.668% (-0.02%) from 64.684%
16829038698

Pull #181

github

web-flow
Merge 265bce697 into 104fa63dd
Pull Request #181: Data dependency analysis: Supersede open definitions

17 of 31 new or added lines in 2 files covered. (54.84%)

2 existing lines in 1 file now uncovered.

8928 of 13806 relevant lines covered (64.67%)

123.59 hits per line

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

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

21
      };
93✔
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) {
69✔
29
    results_.clear();
69✔
30

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

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

39
    for (auto& entry : open_definitions) {
281✔
40
        closed_definitions.insert(entry);
212✔
41
    }
42

43
    for (auto& entry : closed_definitions) {
290✔
44
        if (results_.find(entry.first->container()) == results_.end()) {
221✔
45
            results_.insert({entry.first->container(), {}});
142✔
46
        }
142✔
47
        results_.at(entry.first->container()).insert(entry);
221✔
48
    }
49
};
69✔
50

51
/****** Visitor API ******/
52

53
void DataDependencyAnalysis::visit_block(
159✔
54
    analysis::Users& users,
55
    analysis::AssumptionsAnalysis& assumptions_analysis,
56
    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
) {
61
    auto& dataflow = block.dataflow();
159✔
62

63
    for (auto node : dataflow.topological_sort()) {
389✔
64
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
230✔
65
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
147✔
66
                if (dataflow.in_degree(*node) > 0) {
147✔
67
                    Use use = Use::WRITE;
83✔
68
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
166✔
69
                        if (iedge.type() == data_flow::MemletType::Reference ||
166✔
70
                            iedge.type() == data_flow::MemletType::Dereference_Src) {
83✔
71
                            use = Use::MOVE;
×
72
                            break;
×
73
                        }
74
                    }
75

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

78
                    if (use == Use::WRITE) {
83✔
79
                        // Close all definitions that we supersede
80
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
83✔
81
                        for (auto& user : open_definitions) {
120✔
82
                            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
37✔
83
                                to_close.insert(user);
9✔
84
                            }
9✔
85
                        }
86
                        for (auto& user : to_close) {
92✔
87
                            open_definitions.erase(user.first);
9✔
88
                            closed_definitions.insert(user);
9✔
89
                        }
90

91
                        // Add new definition
92
                        open_definitions.insert({current_user, {}});
83✔
93
                    }
83✔
94
                }
83✔
95
                if (dataflow.out_degree(*access_node) > 0) {
147✔
96
                    Use use = Use::READ;
67✔
97
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
135✔
98
                        if (oedge.type() == data_flow::MemletType::Reference ||
136✔
99
                            oedge.type() == data_flow::MemletType::Dereference_Dst) {
68✔
100
                            use = Use::VIEW;
×
101
                            break;
×
102
                        }
103
                    }
104

105
                    auto current_user = users.get_user(access_node->data(), access_node, use);
67✔
106

107
                    if (use == Use::READ) {
67✔
108
                        // Find all definitions that we read from
109
                        bool found = false;
67✔
110
                        bool superseded_all = false;
67✔
111
                        for (auto& user : open_definitions) {
97✔
112
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
30✔
113
                                user.second.insert(current_user);
10✔
114
                                if (!found) {
10✔
115
                                    found = true;
9✔
116
                                    superseded_all = true;
9✔
117
                                }
9✔
118
                                superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
10✔
119
                            }
10✔
120
                        }
121
                        if (!superseded_all) {
67✔
122
                            undefined.insert(current_user);
60✔
123
                        }
60✔
124
                    }
67✔
125
                }
67✔
126
            }
147✔
127
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
230✔
128
            if (tasklet->is_conditional()) {
83✔
129
                auto& condition = tasklet->condition();
×
130
                for (auto& atom : symbolic::atoms(condition)) {
×
131
                    auto current_user = users.get_user(atom->get_name(), tasklet, Use::READ);
×
132
                    {
133
                        // Find all definitions that we read from
134
                        bool found = false;
×
NEW
135
                        bool superseded_all = false;
×
136
                        for (auto& user : open_definitions) {
×
137
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
138
                                user.second.insert(current_user);
×
NEW
139
                                if (!found) {
×
NEW
140
                                    found = true;
×
NEW
141
                                    superseded_all = true;
×
NEW
142
                                }
×
143

NEW
144
                                superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
×
UNCOV
145
                            }
×
146
                        }
NEW
147
                        if (!superseded_all) {
×
148
                            undefined.insert(current_user);
×
149
                        }
×
150
                    }
151
                }
152
            }
×
153
        } else if (auto library_node = dynamic_cast<data_flow::LibraryNode*>(node)) {
83✔
154
            for (auto& symbol : library_node->symbols()) {
×
155
                auto current_user = users.get_user(symbol->get_name(), library_node, Use::READ);
×
156
                {
157
                    // Find all definitions that we read from
158
                    bool found = false;
×
NEW
159
                    bool superseded_all = false;
×
160
                    for (auto& user : open_definitions) {
×
161
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
162
                            user.second.insert(current_user);
×
NEW
163
                            if (!found) {
×
NEW
164
                                found = true;
×
NEW
165
                                superseded_all = true;
×
NEW
166
                            }
×
NEW
167
                            superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
×
UNCOV
168
                        }
×
169
                    }
NEW
170
                    if (!superseded_all) {
×
171
                        undefined.insert(current_user);
×
172
                    }
×
173
                }
174
            }
175
        }
×
176

177
        for (auto& oedge : dataflow.out_edges(*node)) {
381✔
178
            std::unordered_set<std::string> used;
151✔
179
            for (auto& dim : oedge.subset()) {
282✔
180
                for (auto atom : symbolic::atoms(dim)) {
268✔
181
                    used.insert(atom->get_name());
137✔
182
                }
137✔
183
            }
184
            for (auto& atom : used) {
288✔
185
                auto current_user = users.get_user(atom, &oedge, Use::READ);
137✔
186

187
                {
188
                    // Find all definitions that we read from
189
                    bool found = false;
137✔
190
                    bool superseded_all = false;
137✔
191
                    for (auto& user : open_definitions) {
224✔
192
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
87✔
193
                            user.second.insert(current_user);
4✔
194
                            if (!found) {
4✔
195
                                found = true;
4✔
196
                                superseded_all = true;
4✔
197
                            }
4✔
198
                            superseded_all &= supersedes(*current_user, *user.first, assumptions_analysis);
4✔
199
                        }
4✔
200
                    }
201
                    if (!superseded_all) {
137✔
202
                        undefined.insert(current_user);
133✔
203
                    }
133✔
204
                }
205
            }
206
        }
151✔
207
    }
208
}
159✔
209

210
void DataDependencyAnalysis::visit_for(
65✔
211
    analysis::Users& users,
212
    analysis::AssumptionsAnalysis& assumptions_analysis,
213
    structured_control_flow::StructuredLoop& for_loop,
214
    std::unordered_set<User*>& undefined,
215
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
216
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
217
) {
218
    // Init - Read
219
    for (auto atom : symbolic::atoms(for_loop.init())) {
73✔
220
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
8✔
221

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

234
    // Init - Write
235
    {
236
        // Write Induction Variable
237
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, true);
65✔
238

239
        std::unordered_set<User*> to_close;
65✔
240
        for (auto& user : open_definitions) {
84✔
241
            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
19✔
242
                to_close.insert(user.first);
2✔
243
            }
2✔
244
        }
245
        for (auto& user : to_close) {
67✔
246
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
247
            open_definitions.erase(user);
2✔
248
        }
249
        open_definitions.insert({current_user, {}});
65✔
250

251
        // Improve: If loop is executed at least once, we can close the init's definition
252
        // TODO: Implement this
253
    }
65✔
254

255
    // Update - Write
256
    {
257
        // Exists after loop and inside body
258
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, false, false, true);
65✔
259
        open_definitions.insert({current_user, {}});
65✔
260

261
        // Improve: If loop is executed at least once, we can close the init's definition
262
        // TODO: Implement this
263
    }
264

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

269
        bool found = false;
119✔
270
        for (auto& user : open_definitions) {
375✔
271
            if (user.first->container() == atom->get_name()) {
256✔
272
                user.second.insert(current_user);
131✔
273
                found = true;
131✔
274
            }
131✔
275
        }
276
        if (!found) {
119✔
277
            undefined.insert(current_user);
53✔
278
        }
53✔
279
    }
119✔
280

281
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
65✔
282
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_for;
65✔
283
    std::unordered_set<User*> undefined_for;
65✔
284

285
    // Add assumptions for body
286
    visit_sequence(
65✔
287
        users, assumptions_analysis, for_loop.root(), undefined_for, open_definitions_for, closed_definitions_for
65✔
288
    );
289

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

294
        bool found = false;
65✔
295
        for (auto& user : open_definitions_for) {
187✔
296
            if (user.first->container() == atom->get_name()) {
122✔
297
                user.second.insert(current_user);
1✔
298
                found = true;
1✔
299
            }
1✔
300
        }
301
        if (!found) {
65✔
302
            undefined_for.insert(current_user);
64✔
303
        }
64✔
304
    }
65✔
305

306
    // Merge for with outside
307

308
    // Closed definitions are simply merged
309
    for (auto& entry : closed_definitions_for) {
70✔
310
        closed_definitions.insert(entry);
5✔
311
    }
312

313
    // Undefined reads are matched or forwarded
314
    for (auto open_read : undefined_for) {
474✔
315
        bool found = false;
409✔
316
        for (auto& entry : open_definitions) {
1,446✔
317
            if (intersects(*entry.first, *open_read, assumptions_analysis)) {
1,037✔
318
                entry.second.insert(open_read);
409✔
319
                found = true;
409✔
320
            }
409✔
321
        }
322
        if (!found) {
409✔
323
            undefined.insert(open_read);
204✔
324
        }
204✔
325
    }
326

327
    // Open definitions may close outside open definitions after loop
328
    std::unordered_set<User*> to_close;
65✔
329
    for (auto& previous : open_definitions) {
212✔
330
        for (auto& user : open_definitions_for) {
426✔
331
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
281✔
332
                to_close.insert(previous.first);
2✔
333
                break;
2✔
334
            }
335
        }
336
    }
337
    for (auto& user : to_close) {
67✔
338
        closed_definitions.insert({user, open_definitions.at(user)});
2✔
339
        open_definitions.erase(user);
2✔
340
    }
341

342
    // Add loop-carried dependencies
343

344
    // Criterion 1: Loop is monotonic -> indvar never takes the same value twice
345
    bool is_monotonic = LoopAnalysis::is_monotonic(&for_loop, assumptions_analysis);
65✔
346
    if (is_monotonic) {
65✔
347
        // Case: Can analyze
348
        this->loop_carried_dependencies_.insert({&for_loop, {}});
64✔
349
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
64✔
350

351
        // We can focus on written containers
352

353
        // Case 1: Read-Write between iterations
354
        for (auto& read : undefined_for) {
472✔
355
            for (auto& write : open_definitions_for) {
2,102✔
356
                if (loop_depends(*write.first, *read, assumptions_analysis, for_loop)) {
1,694✔
357
                    if (dependencies.find(read->container()) == dependencies.end()) {
43✔
358
                        dependencies.insert({read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
13✔
359
                    }
13✔
360
                    write.second.insert(read);
43✔
361
                }
43✔
362
            }
363
        }
364

365
        // Case 2: Write-Write between iterations
366
        for (auto& write : open_definitions_for) {
185✔
367
            if (dependencies.find(write.first->container()) != dependencies.end()) {
121✔
368
                continue;
38✔
369
            }
370
            for (auto& write_2 : open_definitions_for) {
260✔
371
                if (loop_depends(*write.first, *write_2.first, assumptions_analysis, for_loop)) {
218✔
372
                    dependencies.insert({write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
41✔
373
                    break;
41✔
374
                }
375
            }
376
        }
377
    } else {
64✔
378
        // Case: Cannot analyze
379
        this->loop_carried_dependencies_.insert({&for_loop, {}});
1✔
380
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
1✔
381

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

400
    // Add open definitions from for to outside
401
    for (auto& entry : open_definitions_for) {
187✔
402
        open_definitions.insert(entry);
122✔
403
    }
404
}
65✔
405

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

420
            bool found = false;
24✔
421
            for (auto& user : open_definitions) {
38✔
422
                if (user.first->container() == atom->get_name()) {
14✔
423
                    user.second.insert(current_user);
7✔
424
                    found = true;
7✔
425
                }
7✔
426
            }
427
            if (!found) {
24✔
428
                undefined.insert(current_user);
17✔
429
            }
17✔
430
        }
24✔
431
    }
37✔
432

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

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

464
    // merge closed writes
465
    for (auto& closing : closed_definitionss_branches) {
58✔
466
        for (auto& entry : closing) {
37✔
467
            closed_definitions.insert(entry);
×
468
        }
469
    }
470

471
    // Close open reads_after_writes for complete branches
472
    if (if_else.is_complete()) {
21✔
473
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
474
        std::unordered_set<std::string> candidates;
16✔
475
        std::unordered_set<std::string> candidates_tmp;
16✔
476

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

490
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
491
            for (auto& entry : open_definitions_branches.at(i)) {
30✔
492
                if (candidates.find(entry.first->container()) != candidates.end()) {
14✔
493
                    candidates_tmp.insert(entry.first->container());
14✔
494
                }
14✔
495
            }
496
            candidates.swap(candidates_tmp);
16✔
497
            candidates_tmp.clear();
16✔
498
        }
16✔
499

500
        for (auto& entry : open_definitions) {
24✔
501
            if (candidates.find(entry.first->container()) != candidates.end()) {
8✔
502
                to_close.insert(entry);
4✔
503
            }
4✔
504
        }
505

506
        for (auto& entry : to_close) {
20✔
507
            open_definitions.erase(entry.first);
4✔
508
            closed_definitions.insert(entry);
4✔
509
        }
510
    } else {
16✔
511
        // Over-Approximation: Add all branch definitions to outer definitions or undefined
512
        // Here we add writes to read sets as "anti-reads"
513
        for (auto& branch : open_definitions_branches) {
10✔
514
            for (auto& def : branch) {
8✔
515
                bool found = false;
3✔
516
                for (auto& entry : open_definitions) {
5✔
517
                    if (intersects(*entry.first, *def.first, assumptions_analysis)) {
2✔
518
                        entry.second.insert(def.first);
2✔
519
                        found = true;
2✔
520
                    }
2✔
521
                }
522
                if (!found) {
3✔
523
                    undefined.insert(def.first);
1✔
524
                }
1✔
525
            }
526
        }
527
    }
528

529
    // merge open reads_after_writes
530
    for (auto& branch : open_definitions_branches) {
58✔
531
        for (auto& entry : branch) {
69✔
532
            open_definitions.insert(entry);
32✔
533
        }
534
    }
535
}
21✔
536

537
void DataDependencyAnalysis::visit_while(
7✔
538
    analysis::Users& users,
539
    analysis::AssumptionsAnalysis& assumptions_analysis,
540
    structured_control_flow::While& while_loop,
541
    std::unordered_set<User*>& undefined,
542
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
543
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
544
) {
545
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
546
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_while;
7✔
547
    std::unordered_set<User*> undefined_while;
7✔
548

549
    visit_sequence(
7✔
550
        users, assumptions_analysis, while_loop.root(), undefined_while, open_definitions_while, closed_definitions_while
7✔
551
    );
552

553
    // Scope-local closed definitions
554
    for (auto& entry : closed_definitions_while) {
9✔
555
        closed_definitions.insert(entry);
2✔
556
    }
557

558
    for (auto open_read : undefined_while) {
9✔
559
        // Over-Approximation: Add loop-carried dependencies for all open reads
560
        for (auto& entry : open_definitions_while) {
5✔
561
            if (entry.first->container() == open_read->container()) {
3✔
562
                entry.second.insert(open_read);
2✔
563
            }
2✔
564
        }
565

566
        // Connect to outside
567
        bool found = false;
2✔
568
        for (auto& entry : open_definitions) {
3✔
569
            if (entry.first->container() == open_read->container()) {
1✔
570
                entry.second.insert(open_read);
1✔
571
                found = true;
1✔
572
            }
1✔
573
        }
574
        if (!found) {
2✔
575
            undefined.insert(open_read);
1✔
576
        }
1✔
577
    }
578

579
    // Add open definitions from while to outside
580
    for (auto& entry : open_definitions_while) {
19✔
581
        open_definitions.insert(entry);
12✔
582
    }
583
}
7✔
584

585
void DataDependencyAnalysis::visit_return(
×
586
    analysis::Users& users,
587
    analysis::AssumptionsAnalysis& assumptions_analysis,
588
    structured_control_flow::Return& return_statement,
589
    std::unordered_set<User*>& undefined,
590
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
591
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
592
) {
593
    // close all open reads_after_writes
594
    for (auto& entry : open_definitions) {
×
595
        closed_definitions.insert(entry);
×
596
    }
597
    open_definitions.clear();
×
598
}
×
599

600
void DataDependencyAnalysis::visit_sequence(
195✔
601
    analysis::Users& users,
602
    analysis::AssumptionsAnalysis& assumptions_analysis,
603
    structured_control_flow::Sequence& sequence,
604
    std::unordered_set<User*>& undefined,
605
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
606
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
607
) {
608
    for (size_t i = 0; i < sequence.size(); i++) {
447✔
609
        auto child = sequence.at(i);
252✔
610
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
252✔
611
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions, closed_definitions);
151✔
612
        } else if (auto for_loop = dynamic_cast<structured_control_flow::StructuredLoop*>(&child.first)) {
252✔
613
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions, closed_definitions);
65✔
614
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
101✔
615
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions, closed_definitions);
21✔
616
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
36✔
617
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions, closed_definitions);
7✔
618
        } else if (auto return_statement = dynamic_cast<structured_control_flow::Return*>(&child.first)) {
15✔
619
            visit_return(users, assumptions_analysis, *return_statement, undefined, open_definitions, closed_definitions);
×
620
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
621
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions, closed_definitions);
×
622
        }
×
623

624
        // handle transitions read
625
        for (auto& entry : child.second.assignments()) {
321✔
626
            for (auto& atom : symbolic::atoms(entry.second)) {
93✔
627
                if (symbolic::is_pointer(atom)) {
24✔
628
                    continue;
×
629
                }
630
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
24✔
631

632
                bool found = false;
24✔
633
                for (auto& user : open_definitions) {
47✔
634
                    if (user.first->container() == atom->get_name()) {
23✔
635
                        user.second.insert(current_user);
22✔
636
                        found = true;
22✔
637
                    }
22✔
638
                }
639
                if (!found) {
24✔
640
                    undefined.insert(current_user);
10✔
641
                }
10✔
642
            }
643
        }
644

645
        // handle transitions write
646
        for (auto& entry : child.second.assignments()) {
321✔
647
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
69✔
648

649
            std::unordered_set<User*> to_close;
69✔
650
            for (auto& user : open_definitions) {
94✔
651
                if (user.first->container() == entry.first->get_name()) {
25✔
652
                    to_close.insert(user.first);
1✔
653
                }
1✔
654
            }
655
            for (auto& user : to_close) {
70✔
656
                closed_definitions.insert({user, open_definitions.at(user)});
1✔
657
                open_definitions.erase(user);
1✔
658
            }
659
            open_definitions.insert({current_user, {}});
69✔
660
        }
69✔
661
    }
252✔
662
}
195✔
663

664
bool DataDependencyAnalysis::loop_depends(
1,912✔
665
    User& previous,
666
    User& current,
667
    analysis::AssumptionsAnalysis& assumptions_analysis,
668
    structured_control_flow::StructuredLoop& loop
669
) {
670
    if (previous.container() != current.container()) {
1,912✔
671
        return false;
1,754✔
672
    }
673
    // Shortcut for scalars
674
    auto& type = this->sdfg_.type(previous.container());
158✔
675
    if (dynamic_cast<const types::Scalar*>(&type)) {
158✔
676
        return true;
40✔
677
    }
678

679
    auto& previous_subsets = previous.subsets();
118✔
680
    auto& current_subsets = current.subsets();
118✔
681

682
    auto previous_scope = Users::scope(&previous);
118✔
683
    auto previous_assumptions = assumptions_analysis.get(loop.root(), *previous_scope, true);
118✔
684
    auto current_scope = Users::scope(&current);
118✔
685
    auto current_assumptions = assumptions_analysis.get(loop.root(), *current_scope, true);
118✔
686

687
    // Check if previous subset is subset of any current subset
688
    for (auto& previous_subset : previous_subsets) {
192✔
689
        for (auto& current_subset : current_subsets) {
193✔
690
            if (symbolic::maps::intersects(
119✔
691
                    previous_subset, current_subset, loop.indvar(), previous_assumptions, current_assumptions
119✔
692
                )) {
693
                return true;
44✔
694
            }
695
        }
696
    }
697

698
    return false;
74✔
699
}
1,912✔
700

701
bool DataDependencyAnalysis::supersedes(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
351✔
702
    if (previous.container() != current.container()) {
351✔
703
        return false;
318✔
704
    }
705
    // Shortcut for scalars
706
    auto& type = this->sdfg_.type(previous.container());
33✔
707
    if (dynamic_cast<const types::Scalar*>(&type)) {
33✔
708
        return true;
14✔
709
    }
710

711
    auto& previous_subsets = previous.subsets();
19✔
712
    auto& current_subsets = current.subsets();
19✔
713
    auto previous_scope = Users::scope(&previous);
19✔
714
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
19✔
715
    auto current_scope = Users::scope(&current);
19✔
716
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
19✔
717

718
    // Check if previous subset is subset of any current subset
719
    for (auto& previous_subset : previous_subsets) {
30✔
720
        bool found = false;
19✔
721
        for (auto& current_subset : current_subsets) {
27✔
722
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions, current_assumptions)) {
19✔
723
                found = true;
11✔
724
                break;
11✔
725
            }
726
        }
727
        if (!found) {
19✔
728
            return false;
8✔
729
        }
730
    }
731

732
    return true;
11✔
733
}
351✔
734

735
bool DataDependencyAnalysis::intersects(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
1,157✔
736
    if (previous.container() != current.container()) {
1,157✔
737
        return false;
726✔
738
    }
739
    // Shortcut for scalars
740
    auto& type = this->sdfg_.type(previous.container());
431✔
741
    if (dynamic_cast<const types::Scalar*>(&type)) {
431✔
742
        return true;
422✔
743
    }
744

745
    auto& previous_subsets = previous.subsets();
9✔
746
    auto& current_subsets = current.subsets();
9✔
747

748
    auto previous_scope = Users::scope(&previous);
9✔
749
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
9✔
750
    auto current_scope = Users::scope(&current);
9✔
751
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
9✔
752

753
    // Check if any current subset intersects with any previous subset
754
    bool found = false;
9✔
755
    for (auto& current_subset : current_subsets) {
15✔
756
        for (auto& previous_subset : previous_subsets) {
15✔
757
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions, previous_assumptions)) {
9✔
758
                found = true;
3✔
759
                break;
3✔
760
            }
761
        }
762
        if (found) {
9✔
763
            break;
3✔
764
        }
765
    }
766

767
    return found;
9✔
768
}
1,157✔
769

770
/****** Public API ******/
771

772
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
773
    assert(write.use() == Use::WRITE);
×
774
    if (results_.find(write.container()) == results_.end()) {
×
775
        return {};
×
776
    }
777
    auto& raws = results_.at(write.container());
×
778
    assert(raws.find(&write) != raws.end());
×
779

780
    auto& reads_for_write = raws.at(&write);
×
781

782
    std::unordered_set<User*> reads;
×
783
    for (auto& entry : reads_for_write) {
×
784
        reads.insert(entry);
×
785
    }
786

787
    return reads;
×
788
};
×
789

790
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(const std::string& container) {
33✔
791
    if (results_.find(container) == results_.end()) {
33✔
792
        return {};
×
793
    }
794
    return results_.at(container);
33✔
795
};
33✔
796

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

800
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
801
    for (auto& entry : reads) {
43✔
802
        for (auto& read : entry.second) {
51✔
803
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
804
                read_to_writes_map[read] = {};
20✔
805
            }
20✔
806
            read_to_writes_map[read].insert(entry.first);
27✔
807
        }
808
    }
809
    return read_to_writes_map;
19✔
810
};
19✔
811

812
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
813
    assert(read.use() == Use::READ);
×
814
    auto definitions = this->definitions(read.container());
×
815

816
    std::unordered_set<User*> writes;
×
817
    for (auto& entry : definitions) {
×
818
        for (auto& r : entry.second) {
×
819
            if (&read == r) {
×
820
                writes.insert(entry.first);
×
821
            }
×
822
        }
823
    }
824
    return writes;
×
825
};
×
826

827
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
828
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
829
};
830

831
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::
832
    dependencies(structured_control_flow::StructuredLoop& loop) const {
50✔
833
    return this->loop_carried_dependencies_.at(&loop);
50✔
834
};
835

836
} // namespace analysis
837
} // 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

© 2025 Coveralls, Inc