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

daisytuner / sdfglib / 18685751061

21 Oct 2025 01:38PM UTC coverage: 61.158% (+0.2%) from 60.927%
18685751061

push

github

web-flow
Merge pull request #290 from daisytuner/storage-types

utilizes storage type for allocations of variables

71 of 117 new or added lines in 6 files covered. (60.68%)

157 existing lines in 6 files now uncovered.

9337 of 15267 relevant lines covered (61.16%)

92.73 hits per line

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

52.21
/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
        if (data_dependency_analysis.is_undefined_user(*define1) ||
4✔
84
            data_dependency_analysis.is_undefined_user(*define2)) {
2✔
UNCOV
85
            continue;
×
86
        }
87

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

114
        // Criterion: One dominates the other
115
        if (!dominance_analysis.dominates(*define1, *define2)) {
2✔
UNCOV
116
            std::swap(define1, define2);
×
UNCOV
117
        }
×
118
        if (!dominance_analysis.dominates(*define1, *define2)) {
2✔
UNCOV
119
            continue;
×
120
        }
121

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

142
            // input1 is constant
143
            if (!users.writes(input->container()).empty() || !users.moves(input->container()).empty() ||
4✔
144
                !users.views(input->container()).empty()) {
2✔
UNCOV
145
                constant_inputs = false;
×
UNCOV
146
                break;
×
147
            }
148

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

162
            // same subsets
163
            if (input->subsets().size() != 1 || input2->subsets().size() != 1) {
2✔
UNCOV
164
                constant_inputs = false;
×
UNCOV
165
                break;
×
166
            }
167

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

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

207
    return applied;
2✔
208
};
2✔
209

210
} // namespace passes
211
} // 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