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

daisytuner / sdfglib / 16069945621

04 Jul 2025 08:56AM UTC coverage: 64.375% (-0.2%) from 64.606%
16069945621

push

github

web-flow
Merge pull request #137 from daisytuner/clang-format

runs clang-format on codebase

609 of 827 new or added lines in 63 files covered. (73.64%)

46 existing lines in 30 files now uncovered.

8578 of 13325 relevant lines covered (64.38%)

177.24 hits per line

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

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

21
      };
92✔
22

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

26
      };
×
27

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

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

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

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

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

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

53
void DataDependencyAnalysis::visit_block(
157✔
54
    analysis::Users& users,
55
    analysis::AssumptionsAnalysis& assumptions_analysis,
56
    structured_control_flow::Block& block,
57
    std::unordered_set<User*>& undefined,
58
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
59
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
60
) {
61
    auto& dataflow = block.dataflow();
157✔
62

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

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

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

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

102
                    if (use == Use::READ) {
66✔
103
                        bool found = false;
66✔
104
                        for (auto& user : open_definitions) {
95✔
105
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
29✔
106
                                user.second.insert(current_user);
9✔
107
                                found = true;
9✔
108
                            }
9✔
109
                        }
110
                        if (!found) {
66✔
111
                            undefined.insert(current_user);
58✔
112
                        }
58✔
113
                    }
66✔
114
                }
66✔
115
            }
144✔
116
        } else if (auto tasklet = dynamic_cast<data_flow::Tasklet*>(node)) {
225✔
117
            if (tasklet->is_conditional()) {
81✔
118
                auto& condition = tasklet->condition();
×
119
                for (auto& atom : symbolic::atoms(condition)) {
×
120
                    auto current_user = users.get_user(atom->get_name(), tasklet, Use::READ);
×
121
                    {
122
                        bool found = false;
×
123
                        for (auto& user : open_definitions) {
×
124
                            if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
125
                                user.second.insert(current_user);
×
126
                                found = true;
×
127
                            }
×
128
                        }
129
                        if (!found) {
×
130
                            undefined.insert(current_user);
×
131
                        }
×
132
                    }
133
                }
134
            }
×
135
        } else if (auto library_node = dynamic_cast<data_flow::LibraryNode*>(node)) {
81✔
136
            for (auto& symbol : library_node->symbols()) {
×
137
                auto current_user = users.get_user(symbol->get_name(), library_node, Use::READ);
×
138
                {
139
                    bool found = false;
×
140
                    for (auto& user : open_definitions) {
×
141
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
×
142
                            user.second.insert(current_user);
×
143
                            found = true;
×
144
                        }
×
145
                    }
146
                    if (!found) {
×
147
                        undefined.insert(current_user);
×
148
                    }
×
149
                }
150
            }
151
        }
×
152

153
        for (auto& oedge : dataflow.out_edges(*node)) {
372✔
154
            std::unordered_set<std::string> used;
147✔
155
            for (auto& dim : oedge.subset()) {
274✔
156
                for (auto atom : symbolic::atoms(dim)) {
260✔
157
                    used.insert(atom->get_name());
133✔
158
                }
133✔
159
            }
160
            for (auto& atom : used) {
280✔
161
                auto current_user = users.get_user(atom, &oedge, Use::READ);
133✔
162

163
                {
164
                    bool found = false;
133✔
165
                    for (auto& user : open_definitions) {
217✔
166
                        if (intersects(*user.first, *current_user, assumptions_analysis)) {
84✔
167
                            user.second.insert(current_user);
4✔
168
                            found = true;
4✔
169
                        }
4✔
170
                    }
171
                    if (!found) {
133✔
172
                        undefined.insert(current_user);
129✔
173
                    }
129✔
174
                }
175
            }
176
        }
147✔
177
    }
178
}
157✔
179

180
void DataDependencyAnalysis::visit_for(
63✔
181
    analysis::Users& users,
182
    analysis::AssumptionsAnalysis& assumptions_analysis,
183
    structured_control_flow::StructuredLoop& for_loop,
184
    std::unordered_set<User*>& undefined,
185
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
186
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
187
) {
188
    // Init - Read
189
    for (auto atom : symbolic::atoms(for_loop.init())) {
71✔
190
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
8✔
191

192
        bool found = false;
8✔
193
        for (auto& user : open_definitions) {
16✔
194
            if (user.first->container() == atom->get_name()) {
8✔
195
                user.second.insert(current_user);
1✔
196
                found = true;
1✔
197
            }
1✔
198
        }
199
        if (!found) {
8✔
200
            undefined.insert(current_user);
7✔
201
        }
7✔
202
    }
8✔
203

204
    // Init - Write
205
    {
206
        // Write Induction Variable
207
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, true);
63✔
208

209
        std::unordered_set<User*> to_close;
63✔
210
        for (auto& user : open_definitions) {
82✔
211
            if (supersedes(*user.first, *current_user, assumptions_analysis)) {
19✔
212
                to_close.insert(user.first);
2✔
213
            }
2✔
214
        }
215
        for (auto& user : to_close) {
65✔
216
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
217
            open_definitions.erase(user);
2✔
218
        }
219
        open_definitions.insert({current_user, {}});
63✔
220

221
        // Improve: If loop is executed at least once, we can close the init's definition
222
        // TODO: Implement this
223
    }
63✔
224

225
    // Update - Write
226
    {
227
        // Exists after loop and inside body
228
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE, false, false, true);
63✔
229
        open_definitions.insert({current_user, {}});
63✔
230

231
        // Improve: If loop is executed at least once, we can close the init's definition
232
        // TODO: Implement this
233
    }
234

235
    // Condition - Read
236
    for (auto atom : symbolic::atoms(for_loop.condition())) {
178✔
237
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
115✔
238

239
        bool found = false;
115✔
240
        for (auto& user : open_definitions) {
363✔
241
            if (user.first->container() == atom->get_name()) {
248✔
242
                user.second.insert(current_user);
127✔
243
                found = true;
127✔
244
            }
127✔
245
        }
246
        if (!found) {
115✔
247
            undefined.insert(current_user);
51✔
248
        }
51✔
249
    }
115✔
250

251
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
63✔
252
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_for;
63✔
253
    std::unordered_set<User*> undefined_for;
63✔
254

255
    // Add assumptions for body
256
    visit_sequence(
63✔
257
        users, assumptions_analysis, for_loop.root(), undefined_for, open_definitions_for, closed_definitions_for
63✔
258
    );
259

260
    // Update - Read
261
    for (auto atom : symbolic::atoms(for_loop.update())) {
126✔
262
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, false, true);
63✔
263

264
        bool found = false;
63✔
265
        for (auto& user : open_definitions_for) {
181✔
266
            if (user.first->container() == atom->get_name()) {
118✔
267
                user.second.insert(current_user);
1✔
268
                found = true;
1✔
269
            }
1✔
270
        }
271
        if (!found) {
63✔
272
            undefined_for.insert(current_user);
62✔
273
        }
62✔
274
    }
63✔
275

276
    // Merge for with outside
277

278
    // Closed definitions are simply merged
279
    for (auto& entry : closed_definitions_for) {
66✔
280
        closed_definitions.insert(entry);
3✔
281
    }
282

283
    // Undefined reads are matched or forwarded
284
    for (auto open_read : undefined_for) {
457✔
285
        bool found = false;
394✔
286
        for (auto& entry : open_definitions) {
1,394✔
287
            if (intersects(*entry.first, *open_read, assumptions_analysis)) {
1,000✔
288
                entry.second.insert(open_read);
395✔
289
                found = true;
395✔
290
            }
395✔
291
        }
292
        if (!found) {
394✔
293
            undefined.insert(open_read);
196✔
294
        }
196✔
295
    }
296

297
    // Open definitions may close outside open definitions after loop
298
    std::unordered_set<User*> to_close;
63✔
299
    for (auto& previous : open_definitions) {
206✔
300
        for (auto& user : open_definitions_for) {
414✔
301
            if (supersedes(*previous.first, *user.first, assumptions_analysis)) {
273✔
302
                to_close.insert(previous.first);
2✔
303
                break;
2✔
304
            }
305
        }
306
    }
307
    for (auto& user : to_close) {
65✔
308
        closed_definitions.insert({user, open_definitions.at(user)});
2✔
309
        open_definitions.erase(user);
2✔
310
    }
311

312
    // Add loop-carried dependencies
313

314
    // Criterion 1: Loop is monotonic -> indvar never takes the same value twice
315
    bool is_monotonic = LoopAnalysis::is_monotonic(&for_loop, assumptions_analysis);
63✔
316
    if (is_monotonic) {
63✔
317
        // Case: Can analyze
318
        this->loop_carried_dependencies_.insert({&for_loop, {}});
62✔
319
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
62✔
320

321
        // We can focus on written containers
322

323
        // Case 1: Read-Write between iterations
324
        for (auto& read : undefined_for) {
455✔
325
            for (auto& write : open_definitions_for) {
2,031✔
326
                if (loop_depends(*write.first, *read, assumptions_analysis, for_loop)) {
1,638✔
327
                    if (dependencies.find(read->container()) == dependencies.end()) {
37✔
328
                        dependencies.insert({read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
11✔
329
                    }
11✔
330
                    write.second.insert(read);
37✔
331
                }
37✔
332
            }
333
        }
334

335
        // Case 2: Write-Write between iterations
336
        for (auto& write : open_definitions_for) {
179✔
337
            if (dependencies.find(write.first->container()) != dependencies.end()) {
117✔
338
                continue;
35✔
339
            }
340
            for (auto& write_2 : open_definitions_for) {
247✔
341
                if (loop_depends(*write.first, *write_2.first, assumptions_analysis, for_loop)) {
205✔
342
                    dependencies.insert({write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
40✔
343
                    break;
40✔
344
                }
345
            }
346
        }
347
    } else {
62✔
348
        // Case: Cannot analyze
349
        this->loop_carried_dependencies_.insert({&for_loop, {}});
1✔
350
        auto& dependencies = this->loop_carried_dependencies_.at(&for_loop);
1✔
351

352
        // Over-Approximation:
353
        // Add loop-carried dependencies for all open reads to all open writes
354
        for (auto& read : undefined_for) {
2✔
355
            for (auto& write : open_definitions_for) {
2✔
356
                if (intersects(*write.first, *read, assumptions_analysis)) {
1✔
357
                    write.second.insert(read);
×
358
                    dependencies.insert({read->container(), LOOP_CARRIED_DEPENDENCY_READ_WRITE});
×
359
                }
×
360
            }
361
        }
362
        // Add loop-carried dependencies for writes
363
        for (auto& write : open_definitions_for) {
2✔
364
            if (dependencies.find(write.first->container()) == dependencies.end()) {
1✔
365
                dependencies.insert({write.first->container(), LOOP_CARRIED_DEPENDENCY_WRITE_WRITE});
1✔
366
            }
1✔
367
        }
368
    }
369

370
    // Add open definitions from for to outside
371
    for (auto& entry : open_definitions_for) {
181✔
372
        open_definitions.insert(entry);
118✔
373
    }
374
}
63✔
375

376
void DataDependencyAnalysis::visit_if_else(
21✔
377
    analysis::Users& users,
378
    analysis::AssumptionsAnalysis& assumptions_analysis,
379
    structured_control_flow::IfElse& if_else,
380
    std::unordered_set<User*>& undefined,
381
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
382
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
383
) {
384
    // Read Conditions
385
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
386
        auto child = if_else.at(i).second;
37✔
387
        for (auto atom : symbolic::atoms(child)) {
61✔
388
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
24✔
389

390
            bool found = false;
24✔
391
            for (auto& user : open_definitions) {
38✔
392
                if (user.first->container() == atom->get_name()) {
14✔
393
                    user.second.insert(current_user);
7✔
394
                    found = true;
7✔
395
                }
7✔
396
            }
397
            if (!found) {
24✔
398
                undefined.insert(current_user);
17✔
399
            }
17✔
400
        }
24✔
401
    }
37✔
402

403
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
21✔
404
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(if_else.size());
21✔
405
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(if_else.size());
21✔
406
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
407
        auto& child = if_else.at(i).first;
37✔
408
        visit_sequence(
37✔
409
            users,
37✔
410
            assumptions_analysis,
37✔
411
            child,
37✔
412
            undefined_branches.at(i),
37✔
413
            open_definitions_branches.at(i),
37✔
414
            closed_definitionss_branches.at(i)
37✔
415
        );
416
    }
37✔
417

418
    // merge partial open reads
419
    for (size_t i = 0; i < if_else.size(); i++) {
58✔
420
        for (auto& entry : undefined_branches.at(i)) {
41✔
421
            bool found = false;
4✔
422
            for (auto& entry2 : open_definitions) {
8✔
423
                if (entry2.first->container() == entry->container()) {
4✔
424
                    entry2.second.insert(entry);
4✔
425
                    found = true;
4✔
426
                }
4✔
427
            }
428
            if (!found) {
4✔
429
                undefined.insert(entry);
×
430
            }
×
431
        }
432
    }
37✔
433

434
    // merge closed writes
435
    for (auto& closing : closed_definitionss_branches) {
58✔
436
        for (auto& entry : closing) {
37✔
437
            closed_definitions.insert(entry);
×
438
        }
439
    }
440

441
    // Close open reads_after_writes for complete branches
442
    if (if_else.is_complete()) {
21✔
443
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
16✔
444
        std::unordered_set<std::string> candidates;
16✔
445
        std::unordered_set<std::string> candidates_tmp;
16✔
446

447
        /* Complete close open reads_after_writes
448
        1. get candidates from first iteration
449
        2. iterate over all branches and prune candidates
450
        3. find prior writes for remaining candidates
451
        4. close open reads_after_writes for all candidates
452
        */
453
        for (auto& entry : open_definitions_branches.at(0)) {
31✔
454
            candidates.insert(entry.first->container());
15✔
455
        }
456
        for (auto& entry : closed_definitionss_branches.at(0)) {
16✔
457
            candidates.insert(entry.first->container());
×
458
        }
459

460
        for (size_t i = 1; i < if_else.size(); i++) {
32✔
461
            for (auto& entry : open_definitions_branches.at(i)) {
30✔
462
                if (candidates.find(entry.first->container()) != candidates.end()) {
14✔
463
                    candidates_tmp.insert(entry.first->container());
14✔
464
                }
14✔
465
            }
466
            candidates.swap(candidates_tmp);
16✔
467
            candidates_tmp.clear();
16✔
468
        }
16✔
469

470
        for (auto& entry : open_definitions) {
24✔
471
            if (candidates.find(entry.first->container()) != candidates.end()) {
8✔
472
                to_close.insert(entry);
4✔
473
            }
4✔
474
        }
475

476
        for (auto& entry : to_close) {
20✔
477
            open_definitions.erase(entry.first);
4✔
478
            closed_definitions.insert(entry);
4✔
479
        }
480
    } else {
16✔
481
        // Over-Approximation: Add all branch definitions to outer definitions or undefined
482
        // Here we add writes to read sets as "anti-reads"
483
        for (auto& branch : open_definitions_branches) {
10✔
484
            for (auto& def : branch) {
8✔
485
                bool found = false;
3✔
486
                for (auto& entry : open_definitions) {
5✔
487
                    if (intersects(*entry.first, *def.first, assumptions_analysis)) {
2✔
488
                        entry.second.insert(def.first);
2✔
489
                        found = true;
2✔
490
                    }
2✔
491
                }
492
                if (!found) {
3✔
493
                    undefined.insert(def.first);
1✔
494
                }
1✔
495
            }
496
        }
497
    }
498

499
    // merge open reads_after_writes
500
    for (auto& branch : open_definitions_branches) {
58✔
501
        for (auto& entry : branch) {
69✔
502
            open_definitions.insert(entry);
32✔
503
        }
504
    }
505
}
21✔
506

507
void DataDependencyAnalysis::visit_while(
7✔
508
    analysis::Users& users,
509
    analysis::AssumptionsAnalysis& assumptions_analysis,
510
    structured_control_flow::While& while_loop,
511
    std::unordered_set<User*>& undefined,
512
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
513
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
514
) {
515
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
516
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_while;
7✔
517
    std::unordered_set<User*> undefined_while;
7✔
518

519
    visit_sequence(
7✔
520
        users, assumptions_analysis, while_loop.root(), undefined_while, open_definitions_while, closed_definitions_while
7✔
521
    );
522

523
    // Scope-local closed definitions
524
    for (auto& entry : closed_definitions_while) {
9✔
525
        closed_definitions.insert(entry);
2✔
526
    }
527

528
    for (auto open_read : undefined_while) {
9✔
529
        // Over-Approximation: Add loop-carried dependencies for all open reads
530
        for (auto& entry : open_definitions_while) {
5✔
531
            if (entry.first->container() == open_read->container()) {
3✔
532
                entry.second.insert(open_read);
2✔
533
            }
2✔
534
        }
535

536
        // Connect to outside
537
        bool found = false;
2✔
538
        for (auto& entry : open_definitions) {
3✔
539
            if (entry.first->container() == open_read->container()) {
1✔
540
                entry.second.insert(open_read);
1✔
541
                found = true;
1✔
542
            }
1✔
543
        }
544
        if (!found) {
2✔
545
            undefined.insert(open_read);
1✔
546
        }
1✔
547
    }
548

549
    // Add open definitions from while to outside
550
    for (auto& entry : open_definitions_while) {
19✔
551
        open_definitions.insert(entry);
12✔
552
    }
553
}
7✔
554

555
void DataDependencyAnalysis::visit_return(
×
556
    analysis::Users& users,
557
    analysis::AssumptionsAnalysis& assumptions_analysis,
558
    structured_control_flow::Return& return_statement,
559
    std::unordered_set<User*>& undefined,
560
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
561
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
562
) {
563
    // close all open reads_after_writes
564
    for (auto& entry : open_definitions) {
×
565
        closed_definitions.insert(entry);
×
566
    }
567
    open_definitions.clear();
×
568
}
×
569

570
void DataDependencyAnalysis::visit_sequence(
192✔
571
    analysis::Users& users,
572
    analysis::AssumptionsAnalysis& assumptions_analysis,
573
    structured_control_flow::Sequence& sequence,
574
    std::unordered_set<User*>& undefined,
575
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
576
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions
577
) {
578
    for (size_t i = 0; i < sequence.size(); i++) {
440✔
579
        auto child = sequence.at(i);
248✔
580
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
248✔
581
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions, closed_definitions);
149✔
582
        } else if (auto for_loop = dynamic_cast<structured_control_flow::StructuredLoop*>(&child.first)) {
248✔
583
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions, closed_definitions);
63✔
584
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
99✔
585
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions, closed_definitions);
21✔
586
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
36✔
587
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions, closed_definitions);
7✔
588
        } else if (auto return_statement = dynamic_cast<structured_control_flow::Return*>(&child.first)) {
15✔
NEW
589
            visit_return(users, assumptions_analysis, *return_statement, undefined, open_definitions, closed_definitions);
×
590
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
NEW
591
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions, closed_definitions);
×
592
        }
×
593

594
        // handle transitions read
595
        for (auto& entry : child.second.assignments()) {
317✔
596
            for (auto& atom : symbolic::atoms(entry.second)) {
93✔
597
                if (symbolic::is_pointer(atom)) {
24✔
598
                    continue;
×
599
                }
600
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
24✔
601

602
                bool found = false;
24✔
603
                for (auto& user : open_definitions) {
47✔
604
                    if (user.first->container() == atom->get_name()) {
23✔
605
                        user.second.insert(current_user);
22✔
606
                        found = true;
22✔
607
                    }
22✔
608
                }
609
                if (!found) {
24✔
610
                    undefined.insert(current_user);
10✔
611
                }
10✔
612
            }
613
        }
614

615
        // handle transitions write
616
        for (auto& entry : child.second.assignments()) {
317✔
617
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
69✔
618

619
            std::unordered_set<User*> to_close;
69✔
620
            for (auto& user : open_definitions) {
94✔
621
                if (user.first->container() == entry.first->get_name()) {
25✔
622
                    to_close.insert(user.first);
1✔
623
                }
1✔
624
            }
625
            for (auto& user : to_close) {
70✔
626
                closed_definitions.insert({user, open_definitions.at(user)});
1✔
627
                open_definitions.erase(user);
1✔
628
            }
629
            open_definitions.insert({current_user, {}});
69✔
630
        }
69✔
631
    }
248✔
632
}
192✔
633

634
bool DataDependencyAnalysis::loop_depends(
1,843✔
635
    User& previous,
636
    User& current,
637
    analysis::AssumptionsAnalysis& assumptions_analysis,
638
    structured_control_flow::StructuredLoop& loop
639
) {
640
    if (previous.container() != current.container()) {
1,843✔
641
        return false;
1,693✔
642
    }
643
    // Shortcut for scalars
644
    auto& type = this->sdfg_.type(previous.container());
150✔
645
    if (dynamic_cast<const types::Scalar*>(&type)) {
150✔
646
        return true;
39✔
647
    }
648

649
    auto& previous_subsets = previous.subsets();
111✔
650
    auto& current_subsets = current.subsets();
111✔
651

652
    auto previous_scope = Users::scope(&previous);
111✔
653
    auto previous_assumptions = assumptions_analysis.get(loop.root(), *previous_scope, true);
111✔
654
    auto current_scope = Users::scope(&current);
111✔
655
    auto current_assumptions = assumptions_analysis.get(loop.root(), *current_scope, true);
111✔
656

657
    // Check if previous subset is subset of any current subset
658
    for (auto& previous_subset : previous_subsets) {
184✔
659
        for (auto& current_subset : current_subsets) {
184✔
660
            if (symbolic::maps::intersects(
111✔
661
                    previous_subset, current_subset, loop.indvar(), previous_assumptions, current_assumptions
111✔
662
                )) {
663
                return true;
38✔
664
            }
665
        }
666
    }
667

668
    return false;
73✔
669
}
1,843✔
670

671
bool DataDependencyAnalysis::supersedes(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
328✔
672
    if (previous.container() != current.container()) {
328✔
673
        return false;
310✔
674
    }
675
    // Shortcut for scalars
676
    auto& type = this->sdfg_.type(previous.container());
18✔
677
    if (dynamic_cast<const types::Scalar*>(&type)) {
18✔
678
        return true;
3✔
679
    }
680

681
    auto& previous_subsets = previous.subsets();
15✔
682
    auto& current_subsets = current.subsets();
15✔
683
    auto previous_scope = Users::scope(&previous);
15✔
684
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
15✔
685
    auto current_scope = Users::scope(&current);
15✔
686
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
15✔
687

688
    // Check if previous subset is subset of any current subset
689
    for (auto& previous_subset : previous_subsets) {
24✔
690
        bool found = false;
15✔
691
        for (auto& current_subset : current_subsets) {
21✔
692
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions, current_assumptions)) {
15✔
693
                found = true;
9✔
694
                break;
9✔
695
            }
696
        }
697
        if (!found) {
15✔
698
            return false;
6✔
699
        }
700
    }
701

702
    return true;
9✔
703
}
328✔
704

705
bool DataDependencyAnalysis::intersects(User& previous, User& current, analysis::AssumptionsAnalysis& assumptions_analysis) {
1,116✔
706
    if (previous.container() != current.container()) {
1,116✔
707
        return false;
701✔
708
    }
709
    // Shortcut for scalars
710
    auto& type = this->sdfg_.type(previous.container());
415✔
711
    if (dynamic_cast<const types::Scalar*>(&type)) {
415✔
712
        return true;
408✔
713
    }
714

715
    auto& previous_subsets = previous.subsets();
7✔
716
    auto& current_subsets = current.subsets();
7✔
717

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

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

737
    return found;
7✔
738
}
1,116✔
739

740
/****** Public API ******/
741

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

750
    auto& reads_for_write = raws.at(&write);
×
751

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

757
    return reads;
×
758
};
×
759

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

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

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

782
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
783
    assert(read.use() == Use::READ);
×
784
    auto definitions = this->definitions(read.container());
×
785

786
    std::unordered_set<User*> writes;
×
787
    for (auto& entry : definitions) {
×
788
        for (auto& r : entry.second) {
×
789
            if (&read == r) {
×
790
                writes.insert(entry.first);
×
791
            }
×
792
        }
793
    }
794
    return writes;
×
795
};
×
796

797
bool DataDependencyAnalysis::available(structured_control_flow::StructuredLoop& loop) const {
×
798
    return this->loop_carried_dependencies_.find(&loop) != this->loop_carried_dependencies_.end();
×
799
};
800

801
const std::unordered_map<std::string, LoopCarriedDependency>& DataDependencyAnalysis::
802
    dependencies(structured_control_flow::StructuredLoop& loop) const {
48✔
803
    return this->loop_carried_dependencies_.at(&loop);
48✔
804
};
805

806
} // namespace analysis
807
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc