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

daisytuner / sdfglib / 18651924023

20 Oct 2025 12:26PM UTC coverage: 60.977% (-0.6%) from 61.539%
18651924023

push

github

web-flow
Merge pull request #286 from daisytuner/reserved-names

removes restricted globals filtering in codegen

8 of 20 new or added lines in 2 files covered. (40.0%)

342 existing lines in 17 files now uncovered.

9174 of 15045 relevant lines covered (60.98%)

92.1 hits per line

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

51.88
/src/passes/dataflow/constant_elimination.cpp
1
#include "sdfg/passes/dataflow/constant_elimination.h"
2

3
#include "sdfg/analysis/data_dependency_analysis.h"
4
#include "sdfg/analysis/dominance_analysis.h"
5
#include "sdfg/analysis/users.h"
6

7
namespace sdfg {
8
namespace passes {
9

10
ConstantElimination::ConstantElimination() : Pass() {};
3✔
11

12
std::string ConstantElimination::name() { return "ConstantElimination"; };
×
13

14
std::unordered_set<analysis::User*>
15
inputs(const std::string& container, data_flow::AccessNode* access_node, analysis::Users& users) {
×
16
    std::unordered_set<analysis::User*> inputs;
×
17

18
    auto& graph = access_node->get_parent();
×
19
    data_flow::Tasklet* tasklet = nullptr;
×
20
    for (auto& iedge : graph.in_edges(*access_node)) {
×
21
        tasklet = dynamic_cast<data_flow::Tasklet*>(&iedge.src());
×
22
    }
23
    if (tasklet == nullptr) {
×
24
        return {};
×
25
    }
26
    for (auto& iedge : graph.in_edges(*tasklet)) {
×
27
        auto& src_node = static_cast<data_flow::AccessNode&>(iedge.src());
×
28
        if (dynamic_cast<data_flow::ConstantNode*>(&src_node) != nullptr) {
×
29
            continue;
×
30
        }
31

32
        inputs.insert(users.get_user(src_node.data(), &src_node, analysis::Use::READ));
×
33
    }
34
    return inputs;
×
35
}
×
36

37
std::unordered_set<analysis::User*>
38
inputs(const std::string& container, structured_control_flow::Transition* transition, analysis::Users& users) {
4✔
39
    std::unordered_set<analysis::User*> inputs;
4✔
40
    auto& assign = transition->assignments().at(symbolic::symbol(container));
4✔
41
    for (auto& sym : symbolic::atoms(assign)) {
10✔
42
        if (symbolic::eq(sym, symbolic::__nullptr__())) {
6✔
43
            continue;
2✔
44
        }
45
        inputs.insert(users.get_user(sym->get_name(), transition, analysis::Use::READ));
4✔
46
    }
47
    return inputs;
4✔
48
}
4✔
49

50
std::unordered_set<analysis::User*> inputs(analysis::User& user, analysis::Users& users) {
4✔
51
    if (auto access_node = dynamic_cast<data_flow::AccessNode*>(user.element())) {
4✔
52
        return inputs(user.container(), access_node, users);
×
53
    } else if (auto transition = dynamic_cast<structured_control_flow::Transition*>(user.element())) {
4✔
54
        return inputs(user.container(), transition, users);
4✔
55
    } else {
56
        return {};
×
57
    }
58
}
4✔
59

60
bool ConstantElimination::run_pass(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
2✔
61
    bool applied = false;
2✔
62

63
    auto& sdfg = builder.subject();
2✔
64
    auto& users = analysis_manager.get<analysis::Users>();
2✔
65
    auto& dominance_analysis = analysis_manager.get<analysis::DominanceAnalysis>();
2✔
66
    auto& data_dependency_analysis = analysis_manager.get<analysis::DataDependencyAnalysis>();
2✔
67

68
    std::unordered_set<std::string> dead;
2✔
69
    for (auto& name : sdfg.containers()) {
6✔
70
        // Criterion: No aliases
71
        if (!users.views(name).empty() || !users.moves(name).empty()) {
4✔
72
            continue;
×
73
        }
74

75
        // Criterion: Two definitions
76
        auto defines = data_dependency_analysis.definitions(name);
4✔
77
        if (defines.size() != 2) {
4✔
78
            continue;
2✔
79
        }
80

81
        auto define1 = defines.begin()->first;
2✔
82
        auto define2 = (++defines.begin())->first;
2✔
83

84
        // Criterion: Identical define
85
        auto subsets1 = define1->subsets();
2✔
86
        auto subsets2 = define2->subsets();
2✔
87
        if (subsets1.size() != 1 || subsets2.size() != 1) {
2✔
88
            continue;
×
89
        }
90
        if (subsets1.begin()->size() != subsets2.begin()->size()) {
2✔
91
            continue;
×
92
        }
93
        bool constant_write = true;
2✔
94
        for (size_t i = 0; i < subsets1.begin()->size(); i++) {
2✔
95
            auto dim1 = subsets1.begin()->at(i);
×
96
            auto dim2 = subsets2.begin()->at(i);
×
97
            if (!symbolic::eq(dim1, dim2)) {
×
98
                constant_write = false;
×
99
                break;
×
100
            }
101
            if (!SymEngine::is_a<SymEngine::Integer>(*dim1)) {
×
102
                constant_write = false;
×
103
                break;
×
104
            }
105
        }
×
106
        if (!constant_write) {
2✔
107
            continue;
×
108
        }
109

110
        // Criterion: One dominates the other
111
        if (!dominance_analysis.dominates(*define1, *define2)) {
2✔
112
            std::swap(define1, define2);
×
113
        }
×
114
        if (!dominance_analysis.dominates(*define1, *define2)) {
2✔
115
            continue;
×
116
        }
117

118
        // Criterion: Inputs of definition are constant
119
        auto inputs1 = inputs(*define1, users);
2✔
120
        if (inputs1.empty()) {
2✔
121
            continue;
×
122
        }
123
        auto inputs2 = inputs(*define2, users);
2✔
124
        if (inputs2.empty()) {
2✔
125
            continue;
×
126
        }
127
        if (inputs1.size() != inputs2.size()) {
2✔
128
            continue;
×
129
        }
130
        bool constant_inputs = true;
2✔
131
        for (auto& input : inputs1) {
4✔
132
            // Recursion
133
            if (input->container() == name) {
2✔
134
                constant_inputs = false;
×
135
                break;
×
136
            }
137

138
            // input1 is constant
139
            if (!users.writes(input->container()).empty() || !users.moves(input->container()).empty() ||
4✔
140
                !users.views(input->container()).empty()) {
2✔
141
                constant_inputs = false;
×
142
                break;
×
143
            }
144

145
            // Find identical input in inputs2
146
            analysis::User* input2 = nullptr;
2✔
147
            for (auto& inp : inputs2) {
2✔
148
                if (input->container() == inp->container()) {
2✔
149
                    input2 = inp;
2✔
150
                    break;
2✔
151
                }
152
            }
153
            if (input2 == nullptr) {
2✔
154
                constant_inputs = false;
×
155
                break;
×
156
            }
157

158
            // same subsets
159
            if (input->subsets().size() != 1 || input2->subsets().size() != 1) {
2✔
160
                constant_inputs = false;
×
161
                break;
×
162
            }
163

164
            auto subset1 = *input->subsets().begin();
2✔
165
            auto subset2 = *input2->subsets().begin();
2✔
166
            if (subset1.size() != subset2.size()) {
2✔
167
                constant_inputs = false;
×
168
                break;
×
169
            }
170
            for (size_t i = 0; i < subset1.size(); i++) {
2✔
171
                auto dim1 = subset1[i];
×
172
                auto dim2 = subset2[i];
×
173
                if (!symbolic::eq(dim1, dim2)) {
×
174
                    constant_inputs = false;
×
175
                    break;
×
176
                }
177
                if (!SymEngine::is_a<SymEngine::Integer>(*dim1)) {
×
178
                    constant_inputs = false;
×
179
                    break;
×
180
                }
181
            }
×
182
        }
2✔
183
        if (!constant_inputs) {
2✔
184
            continue;
×
185
        }
186

187
        // Eliminate the dominated definition
188
        auto write = define2->element();
2✔
189
        if (auto transition = dynamic_cast<structured_control_flow::Transition*>(write)) {
2✔
190
            transition->assignments().erase(symbolic::symbol(name));
2✔
191
            applied = true;
2✔
192
        } else if (auto access_node = dynamic_cast<data_flow::AccessNode*>(write)) {
2✔
193
            auto& graph = access_node->get_parent();
×
194
            if (graph.out_degree(*access_node) > 0) {
×
195
                continue;
×
196
            }
UNCOV
197
            auto& block = dynamic_cast<structured_control_flow::Block&>(*graph.get_parent());
×
UNCOV
198
            builder.clear_node(block, *access_node);
×
UNCOV
199
            applied = true;
×
UNCOV
200
        }
×
201
    }
4✔
202

203
    return applied;
2✔
204
};
2✔
205

206
} // namespace passes
207
} // 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