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

daisytuner / sdfglib / 19224500338

10 Nov 2025 07:48AM UTC coverage: 61.286% (+0.1%) from 61.165%
19224500338

push

github

web-flow
Merge pull request #332 from daisytuner/constant-elimination

handle previous definitions before constants in elimination pass

14 of 19 new or added lines in 1 file covered. (73.68%)

9 existing lines in 4 files now uncovered.

10274 of 16764 relevant lines covered (61.29%)

101.34 hits per line

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

70.07
/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() {};
7✔
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) {
4✔
16
    std::unordered_set<analysis::User*> inputs;
4✔
17

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

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

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

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

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

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

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

75
        // Criterion: Two definitions
76
        auto definitions = data_dependency_analysis.definitions(name);
12✔
77
        if (definitions.size() < 2 || definitions.size() > 3) {
12✔
78
            continue;
6✔
79
        }
80
        // Filter our undefined user
81
        std::unordered_set<analysis::User*> defines;
6✔
82
        for (auto& def : definitions) {
19✔
83
            if (data_dependency_analysis.is_undefined_user(*def.first)) {
13✔
84
                continue;
1✔
85
            }
86
            defines.insert(def.first);
12✔
87
        }
88
        if (defines.size() != 2) {
6✔
UNCOV
89
            continue;
×
90
        }
91
        auto define1 = *defines.begin();
6✔
92
        auto define2 = *(++defines.begin());
6✔
93

94
        // Criterion: Identical define
95
        auto subsets1 = define1->subsets();
6✔
96
        auto subsets2 = define2->subsets();
6✔
97
        if (subsets1.size() != 1 || subsets2.size() != 1) {
6✔
98
            continue;
×
99
        }
100
        if (subsets1.begin()->size() != subsets2.begin()->size()) {
6✔
101
            continue;
×
102
        }
103
        bool constant_write = true;
6✔
104
        for (size_t i = 0; i < subsets1.begin()->size(); i++) {
6✔
105
            auto dim1 = subsets1.begin()->at(i);
×
106
            auto dim2 = subsets2.begin()->at(i);
×
107
            if (!symbolic::eq(dim1, dim2)) {
×
108
                constant_write = false;
×
109
                break;
×
110
            }
111
            if (!SymEngine::is_a<SymEngine::Integer>(*dim1)) {
×
112
                constant_write = false;
×
113
                break;
×
114
            }
115
        }
×
116
        if (!constant_write) {
6✔
117
            continue;
×
118
        }
119

120
        // Criterion: One dominates the other
121
        if (!dominance_analysis.dominates(*define1, *define2)) {
6✔
122
            std::swap(define1, define2);
4✔
123
        }
4✔
124
        if (!dominance_analysis.dominates(*define1, *define2)) {
6✔
125
            continue;
×
126
        }
127

128
        // Criterion: Inputs of definition are constant
129
        auto inputs1 = inputs(*define1, users);
6✔
130
        if (inputs1.empty()) {
6✔
131
            continue;
×
132
        }
133
        auto inputs2 = inputs(*define2, users);
6✔
134
        if (inputs2.empty()) {
6✔
135
            continue;
×
136
        }
137
        if (inputs1.size() != inputs2.size()) {
6✔
138
            continue;
×
139
        }
140
        bool constant_inputs = true;
6✔
141
        for (auto& input : inputs1) {
12✔
142
            // Recursion
143
            if (input->container() == name) {
6✔
144
                constant_inputs = false;
×
145
                break;
×
146
            }
147

148
            // input1 is constant
149
            if (users.views(input->container()).size() > 0) {
6✔
UNCOV
150
                constant_inputs = false;
×
151
                break;
×
152
            }
153
            for (auto& write_user : users.writes(input->container())) {
10✔
154
                if (!dominance_analysis.dominates(*write_user, *define1)) {
4✔
NEW
155
                    constant_inputs = false;
×
NEW
156
                    break;
×
157
                }
158
            }
159
            for (auto& move_user : users.moves(input->container())) {
6✔
NEW
160
                if (!dominance_analysis.dominates(*move_user, *define1)) {
×
NEW
161
                    constant_inputs = false;
×
NEW
162
                    break;
×
163
                }
164
            }
165

166
            // Find identical input in inputs2
167
            analysis::User* input2 = nullptr;
6✔
168
            for (auto& inp : inputs2) {
6✔
169
                if (input->container() == inp->container()) {
6✔
170
                    input2 = inp;
6✔
171
                    break;
6✔
172
                }
173
            }
174
            if (input2 == nullptr) {
6✔
175
                constant_inputs = false;
×
176
                break;
×
177
            }
178

179
            // same subsets
180
            if (input->subsets().size() != 1 || input2->subsets().size() != 1) {
6✔
181
                constant_inputs = false;
×
182
                break;
×
183
            }
184

185
            auto subset1 = *input->subsets().begin();
6✔
186
            auto subset2 = *input2->subsets().begin();
6✔
187
            if (subset1.size() != subset2.size()) {
6✔
188
                constant_inputs = false;
×
189
                break;
×
190
            }
191
            for (size_t i = 0; i < subset1.size(); i++) {
8✔
192
                auto dim1 = subset1[i];
2✔
193
                auto dim2 = subset2[i];
2✔
194
                if (!symbolic::eq(dim1, dim2)) {
2✔
195
                    constant_inputs = false;
×
196
                    break;
×
197
                }
198
                if (!SymEngine::is_a<SymEngine::Integer>(*dim1)) {
2✔
199
                    constant_inputs = false;
×
200
                    break;
×
201
                }
202
            }
2✔
203
        }
6✔
204
        if (!constant_inputs) {
6✔
205
            continue;
×
206
        }
207

208
        // Eliminate the dominated definition
209
        auto write = define2->element();
6✔
210
        if (auto transition = dynamic_cast<structured_control_flow::Transition*>(write)) {
6✔
211
            transition->assignments().erase(symbolic::symbol(name));
4✔
212
            applied = true;
4✔
213
        } else if (auto access_node = dynamic_cast<data_flow::AccessNode*>(write)) {
6✔
214
            auto& graph = access_node->get_parent();
2✔
215
            if (graph.out_degree(*access_node) > 0) {
2✔
216
                continue;
×
217
            }
218
            auto& block = dynamic_cast<structured_control_flow::Block&>(*graph.get_parent());
2✔
219
            builder.clear_node(block, *access_node);
2✔
220
            applied = true;
2✔
221
        }
2✔
222
    }
12✔
223

224
    return applied;
6✔
225
};
6✔
226

227
} // namespace passes
228
} // 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