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

daisytuner / sdfglib / 15781182351

20 Jun 2025 02:27PM UTC coverage: 62.978% (-1.6%) from 64.591%
15781182351

Pull #95

github

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

393 of 500 new or added lines in 10 files covered. (78.6%)

114 existing lines in 7 files now uncovered.

7752 of 12309 relevant lines covered (62.98%)

137.91 hits per line

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

77.7
/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/structured_sdfg.h"
11
#include "sdfg/symbolic/sets.h"
12

13
namespace sdfg {
14
namespace analysis {
15

16
DataDependencyAnalysis::DataDependencyAnalysis(StructuredSDFG& sdfg)
56✔
17
    : Analysis(sdfg), node_(sdfg.root()) {
56✔
18

19
      };
56✔
20

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

25
      };
×
26

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

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

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

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

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

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

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

60
    for (auto node : dataflow.topological_sort()) {
188✔
61
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(node)) {
81✔
62
            if (!symbolic::is_pointer(symbolic::symbol(access_node->data()))) {
43✔
63
                if (dataflow.in_degree(*node) > 0) {
43✔
64
                    Use use = Use::WRITE;
38✔
65
                    for (auto& iedge : dataflow.in_edges(*access_node)) {
76✔
66
                        if (iedge.src_conn() == "refs" || iedge.dst_conn() == "refs") {
38✔
67
                            use = Use::MOVE;
×
68
                            break;
×
69
                        }
70
                    }
71

72
                    auto current_user = users.get_user(access_node->data(), access_node, use);
38✔
73

74
                    if (use == Use::WRITE) {
38✔
75
                        std::unordered_map<User*, std::unordered_set<User*>> to_close;
38✔
76
                        for (auto& user : open_definitions) {
56✔
77
                            if (overwrites(*user.first, *current_user, assumptions_analysis)) {
18✔
78
                                to_close.insert(user);
7✔
79
                            }
7✔
80
                        }
81
                        for (auto& user : to_close) {
45✔
82
                            open_definitions.erase(user.first);
7✔
83
                            closed_definitions.insert(user);
7✔
84
                        }
85
                        open_definitions.insert({current_user, {}});
38✔
86
                    }
38✔
87
                }
38✔
88
                if (dataflow.out_degree(*access_node) > 0) {
43✔
89
                    Use use = Use::READ;
8✔
90
                    for (auto& oedge : dataflow.out_edges(*access_node)) {
16✔
91
                        if (oedge.src_conn() == "refs" || oedge.dst_conn() == "refs") {
8✔
92
                            use = Use::VIEW;
×
93
                            break;
×
94
                        }
95
                    }
96

97
                    auto current_user = users.get_user(access_node->data(), access_node, use);
8✔
98

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

134
        for (auto& oedge : dataflow.out_edges(*node)) {
127✔
135
            std::unordered_set<std::string> used;
46✔
136
            for (auto& dim : oedge.subset()) {
82✔
137
                for (auto atom : symbolic::atoms(dim)) {
43✔
138
                    used.insert(atom->get_name());
7✔
139
                }
7✔
140
            }
141
            for (auto& atom : used) {
53✔
142
                auto current_user = users.get_user(atom, &oedge, Use::READ);
7✔
143

144
                {
145
                    bool found = false;
7✔
146
                    for (auto& user : open_definitions) {
9✔
147
                        if (reads(*user.first, *current_user, assumptions_analysis)) {
2✔
148
                            user.second.insert(current_user);
2✔
149
                            found = true;
2✔
150
                        }
2✔
151
                    }
152
                    if (!found) {
7✔
153
                        undefined.insert(current_user);
5✔
154
                    }
5✔
155
                }
156
            }
157
        }
46✔
158
    }
159
}
107✔
160

161
void DataDependencyAnalysis::visit_for(
13✔
162
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
163
    structured_control_flow::For& for_loop, std::unordered_set<User*>& undefined,
164
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
165
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
166
    // Init - Read
167
    for (auto atom : symbolic::atoms(for_loop.init())) {
14✔
168
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, true);
1✔
169

170
        bool found = false;
1✔
171
        for (auto& user : open_definitions) {
2✔
172
            if (user.first->container() == atom->get_name()) {
1✔
173
                user.second.insert(current_user);
1✔
174
                found = true;
1✔
175
            }
1✔
176
        }
177
        if (!found) {
1✔
NEW
178
            undefined.insert(current_user);
×
179
        }
×
180
    }
1✔
181

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

188
        std::unordered_set<User*> to_close;
13✔
189
        for (auto& user : open_definitions) {
25✔
190
            if (overwrites(*user.first, *current_user, assumptions_analysis)) {
12✔
191
                to_close.insert(user.first);
2✔
192
            }
2✔
193
        }
194
        for (auto& user : to_close) {
15✔
195
            closed_definitions.insert({user, open_definitions.at(user)});
2✔
196
            open_definitions.erase(user);
2✔
197
        }
198
        open_definitions.insert({current_user, {}});
13✔
199

200
        // Improve: If loop is executed at least once, we can close the init's definition
201
        // TODO: Implement this
202
    }
13✔
203

204
    // Update - Write
205
    {
206
        // Exists after loop and inside body
207
        auto current_user = users.get_user(for_loop.indvar()->get_name(), &for_loop, Use::WRITE,
13✔
208
                                           false, false, true);
209
        open_definitions.insert({current_user, {}});
13✔
210

211
        // Improve: If loop is executed at least once, we can close the init's definition
212
        // TODO: Implement this
213
    }
214

215
    // Condition - Read
216
    for (auto atom : symbolic::atoms(for_loop.condition())) {
27✔
217
        auto current_user = users.get_user(atom->get_name(), &for_loop, Use::READ, false, true);
14✔
218

219
        bool found = false;
14✔
220
        for (auto& user : open_definitions) {
53✔
221
            if (user.first->container() == atom->get_name()) {
39✔
222
                user.second.insert(current_user);
27✔
223
                found = true;
27✔
224
            }
27✔
225
        }
226
        if (!found) {
14✔
NEW
227
            undefined.insert(current_user);
×
228
        }
×
229
    }
14✔
230

231
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_for;
13✔
232
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitions_for;
13✔
233
    std::unordered_set<User*> undefined_for;
13✔
234

235
    // Add assumptions for body
236
    visit_sequence(users, assumptions_analysis, for_loop.root(), undefined_for,
13✔
237
                   open_definitions_for, closed_definitions_for);
238

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

244
        bool found = false;
13✔
245
        for (auto& user : open_definitions_for) {
21✔
246
            if (user.first->container() == atom->get_name()) {
8✔
247
                user.second.insert(current_user);
1✔
248
                found = true;
1✔
249
            }
1✔
250
        }
251
        if (!found) {
13✔
252
            undefined_for.insert(current_user);
12✔
253
        }
12✔
254
    }
13✔
255

256
    // Merge for with outside
257

258
    // Closed definitions are scope-local
259
    for (auto& entry : closed_definitions_for) {
13✔
NEW
260
        closed_definitions.insert(entry);
×
261
    }
262

263
    // Handle open reads of for
264
    for (auto open_read : undefined_for) {
30✔
265
        // Adds artificial loop-carried dependencies
266
        for (auto& user : open_definitions_for) {
29✔
267
            if (user.first->container() == open_read->container()) {
12✔
268
                user.second.insert(open_read);
×
269
            }
×
270
        }
271

272
        bool found = false;
17✔
273
        for (auto& entry : open_definitions) {
67✔
274
            if (entry.first->container() == open_read->container()) {
50✔
275
                entry.second.insert(open_read);
34✔
276
                found = true;
34✔
277
            }
34✔
278
        }
279
        if (!found) {
17✔
NEW
280
            undefined.insert(open_read);
×
281
        }
×
282
    }
283

284
    // Close outside open definitions after loop
285
    std::unordered_set<User*> to_close;
13✔
286
    for (auto& user : open_definitions_for) {
21✔
287
        for (auto& previous : open_definitions) {
33✔
288
            if (overwrites(*previous.first, *user.first, assumptions_analysis)) {
25✔
289
                to_close.insert(previous.first);
2✔
290
            }
2✔
291
        }
292
    }
293
    for (auto& user : to_close) {
15✔
294
        closed_definitions.insert({user, open_definitions.at(user)});
2✔
295
        open_definitions.erase(user);
2✔
296
    }
297

298
    // Add open definitions from for to outside
299
    for (auto& entry : open_definitions_for) {
21✔
300
        open_definitions.insert(entry);
8✔
301
    }
302
}
13✔
303

304
void DataDependencyAnalysis::visit_if_else(
18✔
305
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
306
    structured_control_flow::IfElse& if_else, std::unordered_set<User*>& undefined,
307
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
308
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
309
    // Read Conditions
310
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
311
        auto child = if_else.at(i).second;
33✔
312
        for (auto atom : symbolic::atoms(child)) {
54✔
313
            auto current_user = users.get_user(atom->get_name(), &if_else, Use::READ);
21✔
314

315
            bool found = false;
21✔
316
            for (auto& user : open_definitions) {
35✔
317
                if (user.first->container() == atom->get_name()) {
14✔
318
                    user.second.insert(current_user);
7✔
319
                    found = true;
7✔
320
                }
7✔
321
            }
322
            if (!found) {
21✔
323
                undefined.insert(current_user);
14✔
324
            }
14✔
325
        }
21✔
326
    }
33✔
327

328
    std::vector<std::unordered_set<User*>> undefined_branches(if_else.size());
18✔
329
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> open_definitions_branches(
18✔
330
        if_else.size());
18✔
331
    std::vector<std::unordered_map<User*, std::unordered_set<User*>>> closed_definitionss_branches(
18✔
332
        if_else.size());
18✔
333
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
334
        auto& child = if_else.at(i).first;
33✔
335

336
        // Add assumptions for child
337
        visit_sequence(users, assumptions_analysis, child, undefined_branches.at(i),
66✔
338
                       open_definitions_branches.at(i), closed_definitionss_branches.at(i));
33✔
339
    }
33✔
340

341
    // merge partial open reads
342
    for (size_t i = 0; i < if_else.size(); i++) {
51✔
343
        for (auto& entry : undefined_branches.at(i)) {
37✔
344
            bool found = false;
4✔
345
            for (auto& entry2 : open_definitions) {
8✔
346
                if (entry2.first->container() == entry->container()) {
4✔
347
                    entry2.second.insert(entry);
4✔
348
                    found = true;
4✔
349
                }
4✔
350
            }
351
            if (!found) {
4✔
NEW
352
                undefined.insert(entry);
×
353
            }
×
354
        }
355
    }
33✔
356

357
    // merge closed writes
358
    for (auto& closing : closed_definitionss_branches) {
51✔
359
        for (auto& entry : closing) {
33✔
NEW
360
            closed_definitions.insert(entry);
×
361
        }
362
    }
363

364
    // Close open reads_after_writes for complete branches
365
    if (if_else.is_complete()) {
18✔
366
        std::unordered_map<User*, std::unordered_set<User*>> to_close;
15✔
367
        std::unordered_set<std::string> candidates;
15✔
368
        std::unordered_set<std::string> candidates_tmp;
15✔
369

370
        /* Complete close open reads_after_writes
371
        1. get candidates from first iteration
372
        2. iterate over all branches and prune candidates
373
        3. find prior writes for remaining candidates
374
        4. close open reads_after_writes for all candidates
375
        */
376
        for (auto& entry : open_definitions_branches.at(0)) {
29✔
377
            candidates.insert(entry.first->container());
14✔
378
        }
379
        for (auto& entry : closed_definitionss_branches.at(0)) {
15✔
380
            candidates.insert(entry.first->container());
×
381
        }
382

383
        for (size_t i = 1; i < if_else.size(); i++) {
30✔
384
            for (auto& entry : open_definitions_branches.at(i)) {
28✔
385
                if (candidates.find(entry.first->container()) != candidates.end()) {
13✔
386
                    candidates_tmp.insert(entry.first->container());
13✔
387
                }
13✔
388
            }
389
            candidates.swap(candidates_tmp);
15✔
390
            candidates_tmp.clear();
15✔
391
        }
15✔
392

393
        for (auto& entry : open_definitions) {
22✔
394
            if (candidates.find(entry.first->container()) != candidates.end()) {
7✔
395
                to_close.insert(entry);
3✔
396
            }
3✔
397
        }
398

399
        for (auto& entry : to_close) {
18✔
400
            open_definitions.erase(entry.first);
3✔
401
            closed_definitions.insert(entry);
3✔
402
        }
403
    }
15✔
404

405
    // merge open reads_after_writes
406
    for (auto& branch : open_definitions_branches) {
51✔
407
        for (auto& entry : branch) {
61✔
408
            open_definitions.insert(entry);
28✔
409
        }
410
    }
411
}
18✔
412

413
void DataDependencyAnalysis::visit_while(
7✔
414
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
415
    structured_control_flow::While& while_loop, std::unordered_set<User*>& undefined,
416
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
417
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
418
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_while;
7✔
419
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_while;
7✔
420
    std::unordered_set<User*> undefined_while;
7✔
421

422
    // Add assumptions for body
423
    visit_sequence(users, assumptions_analysis, while_loop.root(), undefined_while,
7✔
424
                   open_definitions_while, closed_definitionss_while);
425

426
    for (auto& entry : closed_definitionss_while) {
9✔
427
        closed_definitions.insert(entry);
2✔
428
    }
429

430
    for (auto open_read : undefined_while) {
9✔
431
        // Add recursively to loop
432
        for (auto& entry : open_definitions_while) {
5✔
433
            if (entry.first->container() == open_read->container()) {
3✔
434
                entry.second.insert(open_read);
2✔
435
            }
2✔
436
        }
437

438
        // Add to outside
439
        bool found = false;
2✔
440
        for (auto& entry : open_definitions) {
3✔
441
            if (entry.first->container() == open_read->container()) {
1✔
442
                entry.second.insert(open_read);
1✔
443
                found = true;
1✔
444
            }
1✔
445
        }
446
        if (!found) {
2✔
447
            undefined.insert(open_read);
1✔
448
        }
1✔
449
    }
450

451
    // Keep open reads_after_writes open after loop
452
    for (auto& entry : open_definitions_while) {
19✔
453
        open_definitions.insert(entry);
12✔
454
    }
455
}
7✔
456

NEW
457
void DataDependencyAnalysis::visit_return(
×
458
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
459
    structured_control_flow::Return& return_statement, std::unordered_set<User*>& undefined,
460
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
461
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
462
    // close all open reads_after_writes
NEW
463
    for (auto& entry : open_definitions) {
×
NEW
464
        closed_definitions.insert(entry);
×
465
    }
NEW
466
    open_definitions.clear();
×
467
}
×
468

NEW
469
void DataDependencyAnalysis::visit_map(
×
470
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
471
    structured_control_flow::Map& map, 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
    // write Init
475
    auto current_user = users.get_user(map.indvar()->get_name(), &map, Use::WRITE);
×
476

NEW
477
    open_definitions.insert({current_user, {}});
×
478

NEW
479
    std::unordered_map<User*, std::unordered_set<User*>> open_definitions_map;
×
NEW
480
    std::unordered_map<User*, std::unordered_set<User*>> closed_definitionss_map;
×
NEW
481
    std::unordered_set<User*> undefined_map;
×
482

483
    // Add assumptions for body
NEW
484
    visit_sequence(users, assumptions_analysis, map.root(), undefined_map, open_definitions_map,
×
485
                   closed_definitionss_map);
486

NEW
487
    for (auto& entry : closed_definitionss_map) {
×
NEW
488
        closed_definitions.insert(entry);
×
489
    }
490

491
    // Handle open reads of for
NEW
492
    for (auto open_read : undefined_map) {
×
493
        // Add recursive
NEW
494
        for (auto& user : open_definitions_map) {
×
495
            if (user.first->container() == open_read->container()) {
×
496
                user.second.insert(open_read);
×
497
            }
×
498
        }
499

500
        bool found = false;
×
NEW
501
        for (auto& entry : open_definitions) {
×
502
            if (entry.first->container() == open_read->container()) {
×
503
                entry.second.insert(open_read);
×
504
                found = true;
×
505
            }
×
506
        }
507
        if (!found) {
×
NEW
508
            undefined.insert(open_read);
×
509
        }
×
510
    }
511

512
    // Merge open reads_after_writes
NEW
513
    for (auto& entry : open_definitions_map) {
×
NEW
514
        open_definitions.insert(entry);
×
515
    }
516
}
×
517

518
void DataDependencyAnalysis::visit_sequence(
102✔
519
    analysis::Users& users, analysis::AssumptionsAnalysis& assumptions_analysis,
520
    structured_control_flow::Sequence& sequence, std::unordered_set<User*>& undefined,
521
    std::unordered_map<User*, std::unordered_set<User*>>& open_definitions,
522
    std::unordered_map<User*, std::unordered_set<User*>>& closed_definitions) {
523
    for (size_t i = 0; i < sequence.size(); i++) {
247✔
524
        auto child = sequence.at(i);
145✔
525
        if (auto block = dynamic_cast<structured_control_flow::Block*>(&child.first)) {
145✔
526
            visit_block(users, assumptions_analysis, *block, undefined, open_definitions,
198✔
527
                        closed_definitions);
99✔
528
        } else if (auto for_loop = dynamic_cast<structured_control_flow::For*>(&child.first)) {
145✔
529
            visit_for(users, assumptions_analysis, *for_loop, undefined, open_definitions,
26✔
530
                      closed_definitions);
13✔
531
        } else if (auto if_else = dynamic_cast<structured_control_flow::IfElse*>(&child.first)) {
46✔
532
            visit_if_else(users, assumptions_analysis, *if_else, undefined, open_definitions,
36✔
533
                          closed_definitions);
18✔
534
        } else if (auto while_loop = dynamic_cast<structured_control_flow::While*>(&child.first)) {
33✔
535
            visit_while(users, assumptions_analysis, *while_loop, undefined, open_definitions,
14✔
536
                        closed_definitions);
7✔
537
        } else if (auto return_statement =
15✔
538
                       dynamic_cast<structured_control_flow::Return*>(&child.first)) {
8✔
NEW
539
            visit_return(users, assumptions_analysis, *return_statement, undefined,
×
NEW
540
                         open_definitions, closed_definitions);
×
541
        } else if (auto sequence = dynamic_cast<structured_control_flow::Sequence*>(&child.first)) {
8✔
NEW
542
            visit_sequence(users, assumptions_analysis, *sequence, undefined, open_definitions,
×
NEW
543
                           closed_definitions);
×
544
        } else if (auto map = dynamic_cast<structured_control_flow::Map*>(&child.first)) {
8✔
NEW
545
            visit_map(users, assumptions_analysis, *map, undefined, open_definitions,
×
NEW
546
                      closed_definitions);
×
547
        }
×
548

549
        // handle transitions read
550
        for (auto& entry : child.second.assignments()) {
207✔
551
            for (auto& atom : symbolic::atoms(entry.second)) {
84✔
552
                if (symbolic::is_pointer(atom)) {
22✔
553
                    continue;
×
554
                }
555
                auto current_user = users.get_user(atom->get_name(), &child.second, Use::READ);
22✔
556

557
                bool found = false;
22✔
558
                for (auto& user : open_definitions) {
41✔
559
                    if (user.first->container() == atom->get_name()) {
19✔
560
                        user.second.insert(current_user);
18✔
561
                        found = true;
18✔
562
                    }
18✔
563
                }
564
                if (!found) {
22✔
565
                    undefined.insert(current_user);
10✔
566
                }
10✔
567
            }
568
        }
569

570
        // handle transitions write
571
        for (auto& entry : child.second.assignments()) {
207✔
572
            auto current_user = users.get_user(entry.first->get_name(), &child.second, Use::WRITE);
62✔
573

574
            std::unordered_set<User*> to_close;
62✔
575
            for (auto& user : open_definitions) {
85✔
576
                if (user.first->container() == entry.first->get_name()) {
23✔
577
                    to_close.insert(user.first);
3✔
578
                }
3✔
579
            }
580
            for (auto& user : to_close) {
65✔
581
                closed_definitions.insert({user, open_definitions.at(user)});
3✔
582
                open_definitions.erase(user);
3✔
583
            }
584
            open_definitions.insert({current_user, {}});
62✔
585
        }
62✔
586
    }
145✔
587
}
102✔
588

589
bool DataDependencyAnalysis::overwrites(User& previous, User& current,
55✔
590
                                        analysis::AssumptionsAnalysis& assumptions_analysis) {
591
    if (previous.use() != Use::WRITE || current.use() != Use::WRITE) {
55✔
NEW
592
        return false;
×
593
    }
594
    if (previous.container() != current.container()) {
55✔
595
        return false;
39✔
596
    }
597
    auto& previous_subsets = previous.subsets();
16✔
598
    auto& current_subsets = current.subsets();
16✔
599

600
    auto previous_scope = Users::scope(&previous);
16✔
601
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
16✔
602
    auto current_scope = Users::scope(&current);
16✔
603
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
16✔
604

605
    // Check if previous subset is subset of any current subset
606
    for (auto& previous_subset : previous_subsets) {
27✔
607
        bool found = false;
16✔
608
        for (auto& current_subset : current_subsets) {
21✔
609
            if (symbolic::is_subset(previous_subset, current_subset, previous_assumptions,
16✔
610
                                    current_assumptions)) {
611
                found = true;
11✔
612
                break;
11✔
613
            }
614
        }
615
        if (!found) {
16✔
616
            return false;
5✔
617
        }
618
    }
619

620
    return true;
11✔
621
}
55✔
622

623
bool DataDependencyAnalysis::reads(User& previous, User& current,
5✔
624
                                   analysis::AssumptionsAnalysis& assumptions_analysis) {
625
    if (previous.use() != Use::WRITE || current.use() != Use::READ) {
5✔
NEW
626
        return false;
×
627
    }
628
    if (previous.container() != current.container()) {
5✔
NEW
629
        return false;
×
630
    }
631
    auto& previous_subsets = previous.subsets();
5✔
632
    auto& current_subsets = current.subsets();
5✔
633

634
    auto previous_scope = Users::scope(&previous);
5✔
635
    auto previous_assumptions = assumptions_analysis.get(*previous_scope, true);
5✔
636
    auto current_scope = Users::scope(&current);
5✔
637
    auto current_assumptions = assumptions_analysis.get(*current_scope, true);
5✔
638

639
    // Check if any current subset intersects with any previous subset
640
    bool found = false;
5✔
641
    for (auto& current_subset : current_subsets) {
6✔
642
        for (auto& previous_subset : previous_subsets) {
6✔
643
            if (!symbolic::is_disjoint(current_subset, previous_subset, current_assumptions,
5✔
644
                                       previous_assumptions)) {
645
                found = true;
4✔
646
                break;
4✔
647
            }
648
        }
649
        if (found) {
5✔
650
            break;
4✔
651
        }
652
    }
653

654
    return found;
5✔
655
}
5✔
656

657
/****** Public API ******/
658

NEW
659
std::unordered_set<User*> DataDependencyAnalysis::defines(User& write) {
×
660
    assert(write.use() == Use::WRITE);
×
661
    if (results_.find(write.container()) == results_.end()) {
×
662
        return {};
×
663
    }
664
    auto& raws = results_.at(write.container());
×
665
    assert(raws.find(&write) != raws.end());
×
666

667
    auto& reads_for_write = raws.at(&write);
×
668

669
    std::unordered_set<User*> reads;
×
670
    for (auto& entry : reads_for_write) {
×
671
        reads.insert(entry);
×
672
    }
673

674
    return reads;
×
675
};
×
676

677
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::definitions(
33✔
678
    const std::string& container) {
679
    if (results_.find(container) == results_.end()) {
33✔
680
        return {};
×
681
    }
682
    return results_.at(container);
33✔
683
};
33✔
684

685
std::unordered_map<User*, std::unordered_set<User*>> DataDependencyAnalysis::defined_by(
19✔
686
    const std::string& container) {
687
    auto reads = this->definitions(container);
19✔
688

689
    std::unordered_map<User*, std::unordered_set<User*>> read_to_writes_map;
19✔
690
    for (auto& entry : reads) {
43✔
691
        for (auto& read : entry.second) {
51✔
692
            if (read_to_writes_map.find(read) == read_to_writes_map.end()) {
27✔
693
                read_to_writes_map[read] = {};
20✔
694
            }
20✔
695
            read_to_writes_map[read].insert(entry.first);
27✔
696
        }
697
    }
698
    return read_to_writes_map;
19✔
699
};
19✔
700

NEW
701
std::unordered_set<User*> DataDependencyAnalysis::defined_by(User& read) {
×
NEW
702
    assert(read.use() == Use::READ);
×
NEW
703
    auto definitions = this->definitions(read.container());
×
704

NEW
705
    std::unordered_set<User*> writes;
×
NEW
706
    for (auto& entry : definitions) {
×
NEW
707
        for (auto& r : entry.second) {
×
NEW
708
            if (&read == r) {
×
NEW
709
                writes.insert(entry.first);
×
NEW
710
            }
×
711
        }
712
    }
NEW
713
    return writes;
×
NEW
714
};
×
715

716
}  // namespace analysis
717
}  // 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