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

daisytuner / sdfglib / 15788721511

20 Jun 2025 10:14PM UTC coverage: 64.099% (-0.5%) from 64.591%
15788721511

Pull #95

github

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

983 of 1183 new or added lines in 19 files covered. (83.09%)

52 existing lines in 5 files now uncovered.

8056 of 12568 relevant lines covered (64.1%)

154.64 hits per line

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

80.96
/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
                        std::cout << "Adding read-write dependency for " << read->container()
5✔
311
                                  << std::endl;
5✔
312
                        dependencies.insert(
10✔
313
                            {read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
5✔
314
                    }
5✔
315
                    write.second.insert(read);
5✔
316
                }
5✔
317
            }
318
        }
319

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

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

360
    // Add open definitions from for to outside
361
    for (auto& entry : open_definitions_for) {
92✔
362
        open_definitions.insert(entry);
51✔
363
    }
364
}
41✔
365

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

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

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

398
        // Add assumptions for child
399
        visit_sequence(users, assumptions_analysis, child, undefined_branches.at(i),
66✔
400
                       open_definitions_branches.at(i), closed_definitionss_branches.at(i));
33✔
401
    }
33✔
402

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

419
    // merge closed writes
420
    for (auto& closing : closed_definitionss_branches) {
51✔
421
        for (auto& entry : closing) {
33✔
NEW
422
            closed_definitions.insert(entry);
×
423
        }
424
    }
425

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

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

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

455
        for (auto& entry : open_definitions) {
22✔
456
            if (candidates.find(entry.first->container()) != candidates.end()) {
7✔
457
                to_close.insert(entry);
3✔
458
            }
3✔
459
        }
460

461
        for (auto& entry : to_close) {
18✔
462
            open_definitions.erase(entry.first);
3✔
463
            closed_definitions.insert(entry);
3✔
464
        }
465
    }
15✔
466

467
    // merge open reads_after_writes
468
    for (auto& branch : open_definitions_branches) {
51✔
469
        for (auto& entry : branch) {
61✔
470
            open_definitions.insert(entry);
28✔
471
        }
472
    }
473
}
18✔
474

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

484
    visit_sequence(users, assumptions_analysis, while_loop.root(), undefined_while,
7✔
485
                   open_definitions_while, closed_definitions_while);
486

487
    // Scope-local closed definitions
488
    for (auto& entry : closed_definitions_while) {
9✔
489
        closed_definitions.insert(entry);
2✔
490
    }
491

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

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

513
    // Add open definitions from while to outside
514
    for (auto& entry : open_definitions_while) {
19✔
515
        open_definitions.insert(entry);
12✔
516
    }
517
}
7✔
518

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

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

NEW
539
    open_definitions.insert({current_user, {}});
×
540

NEW
541
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_map;
×
NEW
542
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_map;
×
NEW
543
    std::unordered_set<User*> undefined_map;
×
544

545
    // Add assumptions for body
NEW
546
    visit_sequence(users, assumptions_analysis, map.root(), undefined_map, open_definitions_map,
×
547
                   closed_definitionss_map);
548

NEW
549
    for (auto& entry : closed_definitionss_map) {
×
NEW
550
        closed_definitions.insert(entry);
×
551
    }
552

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

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

574
    // Merge open reads_after_writes
NEW
575
    for (auto& entry : open_definitions_map) {
×
NEW
576
        open_definitions.insert(entry);
×
577
    }
NEW
578
}
×
579

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

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

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

632
        // handle transitions write
633
        for (auto& entry : child.second.assignments()) {
260✔
634
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
62✔
635

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

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

660
    auto previous_scope = Users::scope(&previous);
54✔
661
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
54✔
662
    auto current_scope = Users::scope(&current);
54✔
663
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
54✔
664

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

675
    return false;
35✔
676
}
295✔
677

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

689
    auto previous_scope = Users::scope(&previous);
16✔
690
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
16✔
691
    auto current_scope = Users::scope(&current);
16✔
692
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
16✔
693

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

709
    return true;
11✔
710
}
144✔
711

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

723
    auto previous_scope = Users::scope(&previous);
216✔
724
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
216✔
725
    auto current_scope = Users::scope(&current);
216✔
726
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
216✔
727

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

743
    return found;
216✔
744
}
346✔
745

746
/****** Public API ******/
747

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

NEW
756
    auto& reads_for_write = raws.at(&write);
×
757

NEW
758
    std::unordered_set<User*> reads;
×
NEW
759
    for (auto& entry : reads_for_write) {
×
NEW
760
        reads.insert(entry);
×
761
    }
762

NEW
763
    return reads;
×
NEW
764
};
×
765

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

774
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
775
    const std::string& container) {
776
    auto reads = this->definitions(container);
19✔
777

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

NEW
790
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
NEW
791
    assert(read.use() == Use::READ);
×
NEW
792
    auto definitions = this->definitions(read.container());
×
793

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

NEW
805
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
NEW
806
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
807
};
808

809
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::dependencies(
28✔
810
    structured_control_flow::StructuredLoop& loop) const {
811
    return this->loop_carried_dependencies_.at(&loop);
28✔
812
};
813

814
}  // namespace analysis
815
}  // 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