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

daisytuner / sdfglib / 15793217975

21 Jun 2025 06:56AM UTC coverage: 64.036% (-0.6%) from 64.591%
15793217975

Pull #95

github

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

981 of 1184 new or added lines in 19 files covered. (82.85%)

55 existing lines in 5 files now uncovered.

8048 of 12568 relevant lines covered (64.04%)

149.48 hits per line

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

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

21
      };
79✔
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) {
56✔
30
    results_.clear();
56✔
31

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

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

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

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

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

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

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

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

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

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

101
                    if (use == Use::READ) {
40✔
102
                        bool found = false;
40✔
103
                        for (auto& user : open_definitions) {
48✔
104
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
8✔
105
                                user.second.insert(current_user);
5✔
106
                                found = true;
5✔
107
                            }
5✔
108
                        }
109
                        if (!found) {
40✔
110
                            undefined.insert(current_user);
36✔
111
                        }
36✔
112
                    }
40✔
113
                }
40✔
114
            }
101✔
115
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
165✔
116
            if (tasklet->is_conditional()) {
64✔
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
        }
64✔
135

136
        for (auto& oedge : dataflow.out_edges(*node)) {
269✔
137
            std::unordered_set<std::string> used;
104✔
138
            for (auto& dim : oedge.subset()) {
197✔
139
                for (auto atom : symbolic::atoms(dim)) {
157✔
140
                    used.insert(atom->get_name());
64✔
141
                }
64✔
142
            }
143
            for (auto& atom : used) {
168✔
144
                auto current_user = users.get_user(atom, &oedge, Use::READ);
64✔
145

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

163
void DataDependencyAnalysis::visit_for(
42✔
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())) {
45✔
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 =
42✔
188
            users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, true);
42✔
189

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

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

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

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

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

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

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

258
    // Merge for with outside
259

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

265
    // Undefined reads are matched or forwarded
266
    for (auto open_read : undefined_for) {
203✔
267
        bool found = false;
161✔
268
        for (auto& entry : open_definitions) {
499✔
269
            if (intersects(*entry.first, *open_read, assumptions_analysis)) {
338✔
270
                entry.second.insert(open_read);
214✔
271
                found = true;
214✔
272
            }
214✔
273
        }
274
        if (!found) {
161✔
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;
42✔
281
    for (auto& previous : open_definitions) {
136✔
282
        for (auto& user : open_definitions_for) {
209✔
283
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
117✔
284
                to_close.insert(previous.first);
2✔
285
                break;
2✔
286
            }
287
        }
288
    }
289
    for (auto& user : to_close) {
44✔
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);
42✔
298
    if (is_monotonic) {
42✔
299
        // Case: Can analyze
300
        this->loop_carried_dependencies_.insert({&for_loop, {}});
41✔
301
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
41✔
302

303
        // We can focus on written containers
304

305
        // Case 1: Read-Write between iterations
306
        for (auto& read : undefined_for) {
201✔
307
            for (auto& write : open_definitions_for) {
404✔
308
                if (loop_depends(*write.first, *read, assumptions_analysis, for_loop.indvar())) {
244✔
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) {
94✔
320
            if (dependencies.find(write.first->container()) != dependencies.end()) {
53✔
321
                continue;
12✔
322
            }
323
            for (auto& write_2 : open_definitions_for) {
90✔
324
                if (loop_depends(*write.first, *write_2.first, assumptions_analysis,
64✔
325
                                 for_loop.indvar())) {
64✔
326
                    dependencies.insert(
30✔
327
                        {write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
15✔
328
                    break;
15✔
329
                }
330
            }
331
        }
332
    } else {
41✔
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) {
96✔
358
        open_definitions.insert(entry);
54✔
359
    }
360
}
42✔
361

362
void DataDependencyAnalysis::visit_if_else(
19✔
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++) {
54✔
369
        auto child = if_else.at(i).second;
35✔
370
        for (auto atom : symbolic::atoms(child)) {
58✔
371
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
23✔
372

373
            bool found = false;
23✔
374
            for (auto& user : open_definitions) {
37✔
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) {
23✔
381
                undefined.insert(current_user);
16✔
382
            }
16✔
383
        }
23✔
384
    }
35✔
385

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

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

413
    // merge closed writes
414
    for (auto& closing : closed_definitionss_branches) {
54✔
415
        for (auto& entry : closing) {
35✔
NEW
416
            closed_definitions.insert(entry);
×
417
        }
418
    }
419

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

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

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

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

455
        for (auto& entry : to_close) {
19✔
456
            open_definitions.erase(entry.first);
3✔
457
            closed_definitions.insert(entry);
3✔
458
        }
459
    }
16✔
460

461
    // merge open reads_after_writes
462
    for (auto& branch : open_definitions_branches) {
54✔
463
        for (auto& entry : branch) {
65✔
464
            open_definitions.insert(entry);
30✔
465
        }
466
    }
467
}
19✔
468

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

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

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

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

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

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

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

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

NEW
533
    open_definitions.insert({current_user, {}});
×
534

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

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

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

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

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

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

574
void DataDependencyAnalysis::visit_sequence(
156✔
575
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
576
    structured_control_flow::Sequence& sequence, std::unordered_set<User*>& undefined,
577
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
578
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
579
    for (size_t i = 0; i < sequence.size(); i++) {
359✔
580
        auto child = sequence.at(i);
203✔
581
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
203✔
582
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions,
254✔
583
                        closed_definitions);
127✔
584
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
203✔
585
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions,
84✔
586
                      closed_definitions);
42✔
587
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
76✔
588
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions,
38✔
589
                          closed_definitions);
19✔
590
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
34✔
591
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions,
14✔
592
                        closed_definitions);
7✔
593
        } else if (auto return_statement =
15✔
594
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
8✔
NEW
595
            visit_return(users, assumptions_analysis, *return_statement, undefined,
×
NEW
596
                         open_definitions, closed_definitions);
×
597
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
NEW
598
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions,
×
NEW
599
                           closed_definitions);
×
600
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
8✔
NEW
601
            visit_map(users, assumptions_analysis, *map, undefined, open_definitions,
×
NEW
602
                      closed_definitions);
×
NEW
603
        }
×
604

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

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

626
        // handle transitions write
627
        for (auto& entry : child.second.assignments()) {
267✔
628
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
64✔
629

630
            std::unordered_set<User*> to_close;
64✔
631
            for (auto& user : open_definitions) {
87✔
632
                if (user.first->container() == entry.first->get_name()) {
23✔
633
                    to_close.insert(user.first);
3✔
634
                }
3✔
635
            }
636
            for (auto& user : to_close) {
67✔
637
                closed_definitions.insert({user, open_definitions.at(user)});
3✔
638
                open_definitions.erase(user);
3✔
639
            }
640
            open_definitions.insert({current_user, {}});
64✔
641
        }
64✔
642
    }
203✔
643
}
156✔
644

645
bool DataDependencyAnalysis::loop_depends(User& previous, User& current,
308✔
646
                                          analysis::AssumptionsAnalysis& assumptions_analysis,
647
                                          symbolic::Symbol& indvar) {
648
    if (previous.container() != current.container()) {
308✔
649
        return false;
252✔
650
    }
651
    // Shortcut for scalars
652
    auto& type = this->sdfg_.type(previous.container());
56✔
653
    if (dynamic_cast<const types::Scalar*>(&type)) {
56✔
654
        return true;
13✔
655
    }
656

657
    auto& previous_subsets = previous.subsets();
43✔
658
    auto& current_subsets = current.subsets();
43✔
659

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

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

675
    return false;
36✔
676
}
308✔
677

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

689
    auto& previous_subsets = previous.subsets();
13✔
690
    auto& current_subsets = current.subsets();
13✔
691
    auto previous_scope = Users::scope(&previous);
13✔
692
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
13✔
693
    auto current_scope = Users::scope(&current);
13✔
694
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
13✔
695

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

711
    return true;
8✔
712
}
152✔
713

714
bool DataDependencyAnalysis::intersects(User& previous, User& current,
356✔
715
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
716
    if (previous.container() != current.container()) {
356✔
717
        return false;
132✔
718
    }
719
    // Shortcut for scalars
720
    auto& type = this->sdfg_.type(previous.container());
224✔
721
    if (dynamic_cast<const types::Scalar*>(&type)) {
224✔
722
        return true;
222✔
723
    }
724

725
    auto& previous_subsets = previous.subsets();
2✔
726
    auto& current_subsets = current.subsets();
2✔
727

728
    auto previous_scope = Users::scope(&previous);
2✔
729
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
2✔
730
    auto current_scope = Users::scope(&current);
2✔
731
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
2✔
732

733
    // Check if any current subset intersects with any previous subset
734
    bool found = false;
2✔
735
    for (auto& current_subset : current_subsets) {
3✔
736
        for (auto& previous_subset : previous_subsets) {
3✔
737
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions,
2✔
738
                                       previous_assumptions)) {
739
                found = true;
1✔
740
                break;
1✔
741
            }
742
        }
743
        if (found) {
2✔
744
            break;
1✔
745
        }
746
    }
747

748
    return found;
2✔
749
}
356✔
750

751
/****** Public API ******/
752

NEW
753
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
NEW
754
    assert(write.use() == Use::WRITE);
×
NEW
755
    if (results_.find(write.container()) == results_.end()) {
×
NEW
756
        return {};
×
757
    }
NEW
758
    auto& raws = results_.at(write.container());
×
NEW
759
    assert(raws.find(&write) != raws.end());
×
760

NEW
761
    auto& reads_for_write = raws.at(&write);
×
762

NEW
763
    std::unordered_set<User*> reads;
×
NEW
764
    for (auto& entry : reads_for_write) {
×
NEW
765
        reads.insert(entry);
×
766
    }
767

NEW
768
    return reads;
×
NEW
769
};
×
770

771
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(
33✔
772
    const std::string& container) {
773
    if (results_.find(container) == results_.end()) {
33✔
NEW
774
        return {};
×
775
    }
776
    return results_.at(container);
33✔
777
};
33✔
778

779
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
780
    const std::string& container) {
781
    auto reads = this->definitions(container);
19✔
782

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

NEW
795
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
NEW
796
    assert(read.use() == Use::READ);
×
NEW
797
    auto definitions = this->definitions(read.container());
×
798

NEW
799
    std::unordered_set<User*> writes;
×
NEW
800
    for (auto& entry : definitions) {
×
NEW
801
        for (auto& r : entry.second) {
×
NEW
802
            if (&read == r) {
×
NEW
803
                writes.insert(entry.first);
×
NEW
804
            }
×
805
        }
806
    }
NEW
807
    return writes;
×
NEW
808
};
×
809

NEW
810
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
NEW
811
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
812
};
813

814
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::dependencies(
29✔
815
    structured_control_flow::StructuredLoop& loop) const {
816
    return this->loop_carried_dependencies_.at(&loop);
29✔
817
};
818

819
}  // namespace analysis
820
}  // 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