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

daisytuner / sdfglib / 15788751520

20 Jun 2025 10:17PM UTC coverage: 64.088% (-0.5%) from 64.591%
15788751520

Pull #95

github

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

979 of 1179 new or added lines in 19 files covered. (83.04%)

52 existing lines in 5 files now uncovered.

8052 of 12564 relevant lines covered (64.09%)

154.68 hits per line

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

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

21
      };
78✔
22

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

NEW
27
      };
×
28

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

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

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

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

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

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

55
void DataDependencyAnalysis::visit_block(
132✔
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();
132✔
61

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

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

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

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

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

136
        for (auto& oedge : dataflow.out_edges(*node)) {
264✔
137
            std::unordered_set<std::string> used;
102✔
138
            for (auto& dim : oedge.subset()) {
194✔
139
                for (auto atom : symbolic::atoms(dim)) {
155✔
140
                    used.insert(atom->get_name());
63✔
141
                }
63✔
142
            }
143
            for (auto& atom : used) {
165✔
144
                auto current_user = users.get_user(atom, &oedge, Use::READ);
63✔
145

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

163
void DataDependencyAnalysis::visit_for(
41✔
164
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
165
    structured_control_flow::For& 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())) {
44✔
170
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
3✔
171

172
        bool found = false;
3✔
173
        for (auto& user : open_definitions) {
4✔
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) {
3✔
180
            undefined.insert(current_user);
2✔
181
        }
2✔
182
    }
3✔
183

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

190
        std::unordered_set<User*> to_close;
41✔
191
        for (auto& user : open_definitions) {
53✔
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) {
43✔
197
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
198
            open_definitions.erase(user);
2✔
199
        }
200
        open_definitions.insert({current_user, {}});
41✔
201

202
        // Improve: If loop is executed at least once, we can close the init's definition
203
        // TODO: Implement this
204
    }
41✔
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,
41✔
210
                                           false, false, true);
211
        open_definitions.insert({current_user, {}});
41✔
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())) {
112✔
219
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
71✔
220

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

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

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

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

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

258
    // Merge for with outside
259

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

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

279
    // Open definitions may close outside open definitions after loop
280
    std::unordered_set<User*> to_close;
41✔
281
    for (auto& previous : open_definitions) {
133✔
282
        for (auto& user : open_definitions_for) {
201✔
283
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
111✔
284
                to_close.insert(previous.first);
2✔
285
                break;
2✔
286
            }
287
        }
288
    }
289
    for (auto& user : to_close) {
43✔
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);
41✔
298
    if (is_monotonic) {
41✔
299
        // Case: Can analyze
300
        this->loop_carried_dependencies_.insert({&for_loop, {}});
40✔
301
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
40✔
302

303
        // We can focus on written containers
304

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

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

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

356
    // Add open definitions from for to outside
357
    for (auto& entry : open_definitions_for) {
92✔
358
        open_definitions.insert(entry);
51✔
359
    }
360
}
41✔
361

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

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

386
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
18✔
387
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(
18✔
388
        if_else.size());
18✔
389
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(
18✔
390
        if_else.size());
18✔
391
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
392
        auto& child = if_else.at(i).first;
33✔
393

394
        // Add assumptions for child
395
        visit_sequence(users, assumptions_analysis, child, undefined_branches.at(i),
66✔
396
                       open_definitions_branches.at(i), closed_definitionss_branches.at(i));
33✔
397
    }
33✔
398

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

415
    // merge closed writes
416
    for (auto& closing : closed_definitionss_branches) {
51✔
417
        for (auto& entry : closing) {
33✔
NEW
418
            closed_definitions.insert(entry);
×
419
        }
420
    }
421

422
    // Close open reads_after_writes for complete branches
423
    if (if_else.is_complete()) {
18✔
424
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
15✔
425
        std::unordered_set<std::string> candidates;
15✔
426
        std::unordered_set<std::string> candidates_tmp;
15✔
427

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

441
        for (size_t i = 1; i < if_else.size(); i++) {
30✔
442
            for (auto& entry : open_definitions_branches.at(i)) {
28✔
443
                if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
444
                    candidates_tmp.insert(entry.first->container());
13✔
445
                }
13✔
446
            }
447
            candidates.swap(candidates_tmp);
15✔
448
            candidates_tmp.clear();
15✔
449
        }
15✔
450

451
        for (auto& entry : open_definitions) {
22✔
452
            if (candidates.find(entry.first->container()) != candidates.end()) {
7✔
453
                to_close.insert(entry);
3✔
454
            }
3✔
455
        }
456

457
        for (auto& entry : to_close) {
18✔
458
            open_definitions.erase(entry.first);
3✔
459
            closed_definitions.insert(entry);
3✔
460
        }
461
    }
15✔
462

463
    // merge open reads_after_writes
464
    for (auto& branch : open_definitions_branches) {
51✔
465
        for (auto& entry : branch) {
61✔
466
            open_definitions.insert(entry);
28✔
467
        }
468
    }
469
}
18✔
470

471
void DataDependencyAnalysis::visit_while(
7✔
472
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
473
    structured_control_flow::While& while_loop, std::unordered_set<User*>& undefined,
474
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
475
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
476
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
477
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_while;
7✔
478
    std::unordered_set<User*> undefined_while;
7✔
479

480
    visit_sequence(users, assumptions_analysis, while_loop.root(), undefined_while,
7✔
481
                   open_definitions_while, closed_definitions_while);
482

483
    // Scope-local closed definitions
484
    for (auto& entry : closed_definitions_while) {
9✔
485
        closed_definitions.insert(entry);
2✔
486
    }
487

488
    for (auto open_read : undefined_while) {
9✔
489
        // Over-Approximation: Add loop-carried dependencies for all open reads
490
        for (auto& entry : open_definitions_while) {
5✔
491
            if (entry.first->container() == open_read->container()) {
3✔
492
                entry.second.insert(open_read);
2✔
493
            }
2✔
494
        }
495

496
        // Connect to outside
497
        bool found = false;
2✔
498
        for (auto& entry : open_definitions) {
3✔
499
            if (entry.first->container() == open_read->container()) {
1✔
500
                entry.second.insert(open_read);
1✔
501
                found = true;
1✔
502
            }
1✔
503
        }
504
        if (!found) {
2✔
505
            undefined.insert(open_read);
1✔
506
        }
1✔
507
    }
508

509
    // Add open definitions from while to outside
510
    for (auto& entry : open_definitions_while) {
19✔
511
        open_definitions.insert(entry);
12✔
512
    }
513
}
7✔
514

NEW
515
void DataDependencyAnalysis::visit_return(
×
516
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
517
    structured_control_flow::Return& return_statement, std::unordered_set<User*>& undefined,
518
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
519
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
520
    // close all open reads_after_writes
NEW
521
    for (auto& entry : open_definitions) {
×
NEW
522
        closed_definitions.insert(entry);
×
523
    }
NEW
524
    open_definitions.clear();
×
NEW
525
}
×
526

NEW
527
void DataDependencyAnalysis::visit_map(
×
528
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
529
    structured_control_flow::Map& map, std::unordered_set<User*>& undefined,
530
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
531
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
532
    // write Init
NEW
533
    auto current_user = users.get_user(map.indvar()->get_name(), &map, Use::WRITE);
×
534

NEW
535
    open_definitions.insert({current_user, {}});
×
536

NEW
537
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_map;
×
NEW
538
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_map;
×
NEW
539
    std::unordered_set<User*> undefined_map;
×
540

541
    // Add assumptions for body
NEW
542
    visit_sequence(users, assumptions_analysis, map.root(), undefined_map, open_definitions_map,
×
543
                   closed_definitionss_map);
544

NEW
545
    for (auto& entry : closed_definitionss_map) {
×
NEW
546
        closed_definitions.insert(entry);
×
547
    }
548

549
    // Handle open reads of for
NEW
550
    for (auto open_read : undefined_map) {
×
551
        // Add recursive
NEW
552
        for (auto& user : open_definitions_map) {
×
NEW
553
            if (user.first->container() == open_read->container()) {
×
NEW
554
                user.second.insert(open_read);
×
NEW
555
            }
×
556
        }
557

NEW
558
        bool found = false;
×
NEW
559
        for (auto& entry : open_definitions) {
×
NEW
560
            if (entry.first->container() == open_read->container()) {
×
NEW
561
                entry.second.insert(open_read);
×
NEW
562
                found = true;
×
NEW
563
            }
×
564
        }
NEW
565
        if (!found) {
×
NEW
566
            undefined.insert(open_read);
×
NEW
567
        }
×
568
    }
569

570
    // Merge open reads_after_writes
NEW
571
    for (auto& entry : open_definitions_map) {
×
NEW
572
        open_definitions.insert(entry);
×
573
    }
NEW
574
}
×
575

576
void DataDependencyAnalysis::visit_sequence(
152✔
577
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
578
    structured_control_flow::Sequence& sequence, std::unordered_set<User*>& undefined,
579
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
580
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
581
    for (size_t i = 0; i < sequence.size(); i++) {
350✔
582
        auto child = sequence.at(i);
198✔
583
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
198✔
584
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions,
248✔
585
                        closed_definitions);
124✔
586
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
198✔
587
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions,
82✔
588
                      closed_definitions);
41✔
589
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
74✔
590
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions,
36✔
591
                          closed_definitions);
18✔
592
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
33✔
593
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions,
14✔
594
                        closed_definitions);
7✔
595
        } else if (auto return_statement =
15✔
596
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
8✔
NEW
597
            visit_return(users, assumptions_analysis, *return_statement, undefined,
×
NEW
598
                         open_definitions, closed_definitions);
×
599
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
NEW
600
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions,
×
NEW
601
                           closed_definitions);
×
602
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
8✔
NEW
603
            visit_map(users, assumptions_analysis, *map, undefined, open_definitions,
×
NEW
604
                      closed_definitions);
×
NEW
605
        }
×
606

607
        // handle transitions read
608
        for (auto& entry : child.second.assignments()) {
260✔
609
            for (auto& atom : symbolic::atoms(entry.second)) {
84✔
610
                if (symbolic::is_pointer(atom)) {
22✔
NEW
611
                    continue;
×
612
                }
613
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
22✔
614

615
                bool found = false;
22✔
616
                for (auto& user : open_definitions) {
41✔
617
                    if (user.first->container() == atom->get_name()) {
19✔
618
                        user.second.insert(current_user);
18✔
619
                        found = true;
18✔
620
                    }
18✔
621
                }
622
                if (!found) {
22✔
623
                    undefined.insert(current_user);
10✔
624
                }
10✔
625
            }
626
        }
627

628
        // handle transitions write
629
        for (auto& entry : child.second.assignments()) {
260✔
630
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
62✔
631

632
            std::unordered_set<User*> to_close;
62✔
633
            for (auto& user : open_definitions) {
85✔
634
                if (user.first->container() == entry.first->get_name()) {
23✔
635
                    to_close.insert(user.first);
3✔
636
                }
3✔
637
            }
638
            for (auto& user : to_close) {
65✔
639
                closed_definitions.insert({user, open_definitions.at(user)});
3✔
640
                open_definitions.erase(user);
3✔
641
            }
642
            open_definitions.insert({current_user, {}});
62✔
643
        }
62✔
644
    }
198✔
645
}
152✔
646

647
bool DataDependencyAnalysis::loop_depends(User& previous, User& current,
295✔
648
                                          analysis::AssumptionsAnalysis& assumptions_analysis,
649
                                          symbolic::Symbol& indvar) {
650
    if (previous.container() != current.container()) {
295✔
651
        return false;
241✔
652
    }
653
    auto& previous_subsets = previous.subsets();
54✔
654
    auto& current_subsets = current.subsets();
54✔
655

656
    auto previous_scope = Users::scope(&previous);
54✔
657
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
54✔
658
    auto current_scope = Users::scope(&current);
54✔
659
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
54✔
660

661
    // Check if previous subset is subset of any current subset
662
    for (auto& previous_subset : previous_subsets) {
89✔
663
        for (auto& current_subset : current_subsets) {
89✔
664
            if (symbolic::intersects(previous_subset, current_subset, indvar, previous_assumptions,
54✔
665
                                     current_assumptions)) {
666
                return true;
19✔
667
            }
668
        }
669
    }
670

671
    return false;
35✔
672
}
295✔
673

674
bool DataDependencyAnalysis::supersedes(User& previous, User& current,
144✔
675
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
676
    if (previous.use() != Use::WRITE || current.use() != Use::WRITE) {
144✔
NEW
677
        return false;
×
678
    }
679
    if (previous.container() != current.container()) {
144✔
680
        return false;
128✔
681
    }
682
    auto& previous_subsets = previous.subsets();
16✔
683
    auto& current_subsets = current.subsets();
16✔
684

685
    auto previous_scope = Users::scope(&previous);
16✔
686
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
16✔
687
    auto current_scope = Users::scope(&current);
16✔
688
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
16✔
689

690
    // Check if previous subset is subset of any current subset
691
    for (auto& previous_subset : previous_subsets) {
27✔
692
        bool found = false;
16✔
693
        for (auto& current_subset : current_subsets) {
21✔
694
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions,
16✔
695
                                    current_assumptions)) {
696
                found = true;
11✔
697
                break;
11✔
698
            }
699
        }
700
        if (!found) {
16✔
701
            return false;
5✔
702
        }
703
    }
704

705
    return true;
11✔
706
}
144✔
707

708
bool DataDependencyAnalysis::intersects(User& previous, User& current,
346✔
709
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
710
    if (previous.use() != Use::WRITE || current.use() != Use::READ) {
346✔
NEW
711
        return false;
×
712
    }
713
    if (previous.container() != current.container()) {
346✔
714
        return false;
130✔
715
    }
716
    auto& previous_subsets = previous.subsets();
216✔
717
    auto& current_subsets = current.subsets();
216✔
718

719
    auto previous_scope = Users::scope(&previous);
216✔
720
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
216✔
721
    auto current_scope = Users::scope(&current);
216✔
722
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
216✔
723

724
    // Check if any current subset intersects with any previous subset
725
    bool found = false;
216✔
726
    for (auto& current_subset : current_subsets) {
217✔
727
        for (auto& previous_subset : previous_subsets) {
217✔
728
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions,
216✔
729
                                       previous_assumptions)) {
730
                found = true;
215✔
731
                break;
215✔
732
            }
733
        }
734
        if (found) {
216✔
735
            break;
215✔
736
        }
737
    }
738

739
    return found;
216✔
740
}
346✔
741

742
/****** Public API ******/
743

NEW
744
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
NEW
745
    assert(write.use() == Use::WRITE);
×
NEW
746
    if (results_.find(write.container()) == results_.end()) {
×
NEW
747
        return {};
×
748
    }
NEW
749
    auto& raws = results_.at(write.container());
×
NEW
750
    assert(raws.find(&write) != raws.end());
×
751

NEW
752
    auto& reads_for_write = raws.at(&write);
×
753

NEW
754
    std::unordered_set<User*> reads;
×
NEW
755
    for (auto& entry : reads_for_write) {
×
NEW
756
        reads.insert(entry);
×
757
    }
758

NEW
759
    return reads;
×
NEW
760
};
×
761

762
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(
33✔
763
    const std::string& container) {
764
    if (results_.find(container) == results_.end()) {
33✔
NEW
765
        return {};
×
766
    }
767
    return results_.at(container);
33✔
768
};
33✔
769

770
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
771
    const std::string& container) {
772
    auto reads = this->definitions(container);
19✔
773

774
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
775
    for (auto& entry : reads) {
43✔
776
        for (auto& read : entry.second) {
51✔
777
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
778
                read_to_writes_map[read] = {};
20✔
779
            }
20✔
780
            read_to_writes_map[read].insert(entry.first);
27✔
781
        }
782
    }
783
    return read_to_writes_map;
19✔
784
};
19✔
785

NEW
786
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
NEW
787
    assert(read.use() == Use::READ);
×
NEW
788
    auto definitions = this->definitions(read.container());
×
789

NEW
790
    std::unordered_set<User*> writes;
×
NEW
791
    for (auto& entry : definitions) {
×
NEW
792
        for (auto& r : entry.second) {
×
NEW
793
            if (&read == r) {
×
NEW
794
                writes.insert(entry.first);
×
NEW
795
            }
×
796
        }
797
    }
NEW
798
    return writes;
×
NEW
799
};
×
800

NEW
801
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
NEW
802
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
803
};
804

805
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::dependencies(
28✔
806
    structured_control_flow::StructuredLoop& loop) const {
807
    return this->loop_carried_dependencies_.at(&loop);
28✔
808
};
809

810
}  // namespace analysis
811
}  // 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