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

daisytuner / sdfglib / 20764569418

06 Jan 2026 10:50PM UTC coverage: 62.168% (+21.4%) from 40.764%
20764569418

push

github

web-flow
Merge pull request #433 from daisytuner/clang-coverage

updates clang coverage flags

14988 of 24109 relevant lines covered (62.17%)

88.57 hits per line

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

81.28
/src/data_flow/library_nodes/math/tensor/elementwise_node.cpp
1
#include "sdfg/data_flow/library_nodes/math/tensor/elementwise_node.h"
2

3
#include "sdfg/analysis/analysis.h"
4
#include "sdfg/builder/structured_sdfg_builder.h"
5

6
#include "sdfg/analysis/scope_analysis.h"
7

8
namespace sdfg {
9
namespace math {
10
namespace tensor {
11

12
ElementWiseUnaryNode::ElementWiseUnaryNode(
13
    size_t element_id,
14
    const DebugInfo& debug_info,
15
    const graph::Vertex vertex,
16
    data_flow::DataFlowGraph& parent,
17
    const data_flow::LibraryNodeCode& code,
18
    const std::vector<symbolic::Expression>& shape
19
)
20
    : TensorNode(element_id, debug_info, vertex, parent, code, {"Y"}, {"X"}, data_flow::ImplementationType_NONE),
76✔
21
      shape_(shape) {}
76✔
22

23
symbolic::SymbolSet ElementWiseUnaryNode::symbols() const {
2✔
24
    symbolic::SymbolSet syms;
2✔
25
    for (const auto& dim : shape_) {
4✔
26
        for (auto& atom : symbolic::atoms(dim)) {
4✔
27
            syms.insert(atom);
×
28
        }
×
29
    }
4✔
30
    return syms;
2✔
31
}
2✔
32

33
void ElementWiseUnaryNode::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
×
34
    for (auto& dim : shape_) {
×
35
        dim = symbolic::subs(dim, old_expression, new_expression);
×
36
    }
×
37
}
×
38

39
bool ElementWiseUnaryNode::expand(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
70✔
40
    auto& dataflow = this->get_parent();
70✔
41
    auto& block = static_cast<structured_control_flow::Block&>(*dataflow.get_parent());
70✔
42
    if (dataflow.in_degree(*this) != 1 || dataflow.out_degree(*this) != 1) {
70✔
43
        return false;
×
44
    }
×
45

46
    auto& scope_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
70✔
47
    auto& parent = static_cast<structured_control_flow::Sequence&>(*scope_analysis.parent_scope(&block));
70✔
48
    int index = parent.index(block);
70✔
49
    auto& transition = parent.at(index).second;
70✔
50

51
    auto& input = this->inputs_.at(0);
70✔
52
    auto& output = this->outputs_.at(0);
70✔
53

54
    auto& iedge = *dataflow.in_edges(*this).begin();
70✔
55
    auto& oedge = *dataflow.out_edges(*this).begin();
70✔
56

57
    // Checks if legal
58
    auto& input_node = static_cast<data_flow::AccessNode&>(iedge.src());
70✔
59
    auto& output_node = static_cast<data_flow::AccessNode&>(oedge.dst());
70✔
60
    if (dataflow.in_degree(input_node) != 0 || dataflow.out_degree(output_node) != 0) {
70✔
61
        return false;
×
62
    }
×
63

64
    // Add new graph after the current block
65
    auto& new_sequence = builder.add_sequence_before(parent, block, transition.assignments(), block.debug_info());
70✔
66

67
    // Add maps
68
    data_flow::Subset new_subset;
70✔
69
    structured_control_flow::Sequence* last_scope = &new_sequence;
70✔
70
    structured_control_flow::Map* last_map = nullptr;
70✔
71
    std::vector<symbolic::Expression> loop_vars;
70✔
72

73
    for (size_t i = 0; i < this->shape_.size(); i++) {
236✔
74
        std::string indvar_str = builder.find_new_name("_i");
166✔
75
        builder.add_container(indvar_str, types::Scalar(types::PrimitiveType::UInt64));
166✔
76

77
        auto indvar = symbolic::symbol(indvar_str);
166✔
78
        auto init = symbolic::zero();
166✔
79
        auto update = symbolic::add(indvar, symbolic::one());
166✔
80
        auto condition = symbolic::Lt(indvar, this->shape_[i]);
166✔
81
        last_map = &builder.add_map(
166✔
82
            *last_scope,
166✔
83
            indvar,
166✔
84
            condition,
166✔
85
            init,
166✔
86
            update,
166✔
87
            structured_control_flow::ScheduleType_Sequential::create(),
166✔
88
            {},
166✔
89
            block.debug_info()
166✔
90
        );
166✔
91
        last_scope = &last_map->root();
166✔
92

93
        loop_vars.push_back(indvar);
166✔
94
    }
166✔
95

96
    // Linearize subset
97
    symbolic::Expression linear_index = symbolic::zero();
70✔
98
    for (size_t i = 0; i < this->shape_.size(); ++i) {
236✔
99
        linear_index = symbolic::add(symbolic::mul(linear_index, this->shape_[i]), loop_vars[i]);
166✔
100
    }
166✔
101
    if (!this->shape_.empty()) {
70✔
102
        new_subset.push_back(linear_index);
70✔
103
    }
70✔
104

105
    bool success = this->expand_operation(
70✔
106
        builder,
70✔
107
        analysis_manager,
70✔
108
        *last_scope,
70✔
109
        input_node.data(),
70✔
110
        output_node.data(),
70✔
111
        iedge.base_type(),
70✔
112
        oedge.base_type(),
70✔
113
        new_subset
70✔
114
    );
70✔
115
    if (!success) {
70✔
116
        return false;
×
117
    }
×
118

119
    // Clean up block
120
    builder.remove_memlet(block, iedge);
70✔
121
    builder.remove_memlet(block, oedge);
70✔
122
    builder.remove_node(block, input_node);
70✔
123
    builder.remove_node(block, output_node);
70✔
124
    builder.remove_node(block, *this);
70✔
125
    builder.remove_child(parent, index + 1);
70✔
126

127
    return true;
70✔
128
}
70✔
129

130
ElementWiseBinaryNode::ElementWiseBinaryNode(
131
    size_t element_id,
132
    const DebugInfo& debug_info,
133
    const graph::Vertex vertex,
134
    data_flow::DataFlowGraph& parent,
135
    const data_flow::LibraryNodeCode& code,
136
    const std::vector<symbolic::Expression>& shape
137
)
138
    : TensorNode(element_id, debug_info, vertex, parent, code, {"C"}, {"A", "B"}, data_flow::ImplementationType_NONE),
42✔
139
      shape_(shape) {}
42✔
140

141
symbolic::SymbolSet ElementWiseBinaryNode::symbols() const {
×
142
    symbolic::SymbolSet syms;
×
143
    for (const auto& dim : shape_) {
×
144
        for (auto& atom : symbolic::atoms(dim)) {
×
145
            syms.insert(atom);
×
146
        }
×
147
    }
×
148
    return syms;
×
149
}
×
150

151
void ElementWiseBinaryNode::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
×
152
    for (auto& dim : shape_) {
×
153
        dim = symbolic::subs(dim, old_expression, new_expression);
×
154
    }
×
155
}
×
156

157
bool ElementWiseBinaryNode::expand(builder::StructuredSDFGBuilder& builder, analysis::AnalysisManager& analysis_manager) {
31✔
158
    auto& dataflow = this->get_parent();
31✔
159
    auto& block = static_cast<structured_control_flow::Block&>(*dataflow.get_parent());
31✔
160
    if (dataflow.in_degree(*this) != 2 || dataflow.out_degree(*this) != 1) {
31✔
161
        return false;
×
162
    }
×
163
    auto& scope_analysis = analysis_manager.get<analysis::ScopeAnalysis>();
31✔
164
    auto& parent = static_cast<structured_control_flow::Sequence&>(*scope_analysis.parent_scope(&block));
31✔
165
    int index = parent.index(block);
31✔
166
    auto& transition = parent.at(index).second;
31✔
167

168
    auto& input_a = this->inputs_.at(0);
31✔
169
    auto& input_b = this->inputs_.at(1);
31✔
170
    auto& output = this->outputs_.at(0);
31✔
171

172
    auto iedge_a = &(*dataflow.in_edges(*this).begin());
31✔
173
    auto iedge_b = &(*(++dataflow.in_edges(*this).begin()));
31✔
174
    if (iedge_a->dst_conn() != "A") {
31✔
175
        std::swap(iedge_a, iedge_b);
×
176
    }
×
177
    auto& oedge = *dataflow.out_edges(*this).begin();
31✔
178

179
    // Checks if legal
180
    auto& input_node_a = static_cast<data_flow::AccessNode&>(iedge_a->src());
31✔
181
    auto& input_node_b = static_cast<data_flow::AccessNode&>(iedge_b->src());
31✔
182
    auto& output_node = static_cast<data_flow::AccessNode&>(oedge.dst());
31✔
183
    if (dataflow.in_degree(input_node_a) != 0 || dataflow.in_degree(input_node_b) != 0 ||
31✔
184
        dataflow.out_degree(output_node) != 0) {
31✔
185
        return false;
×
186
    }
×
187

188
    // Add new graph after the current block
189
    auto& new_sequence = builder.add_sequence_before(parent, block, transition.assignments(), block.debug_info());
31✔
190

191
    // Add maps
192
    data_flow::Subset new_subset;
31✔
193
    structured_control_flow::Sequence* last_scope = &new_sequence;
31✔
194
    structured_control_flow::Map* last_map = nullptr;
31✔
195
    std::vector<symbolic::Expression> loop_vars;
31✔
196

197
    for (size_t i = 0; i < this->shape_.size(); i++) {
92✔
198
        std::string indvar_str = builder.find_new_name("_i");
61✔
199
        builder.add_container(indvar_str, types::Scalar(types::PrimitiveType::UInt64));
61✔
200

201
        auto indvar = symbolic::symbol(indvar_str);
61✔
202
        auto init = symbolic::zero();
61✔
203
        auto update = symbolic::add(indvar, symbolic::one());
61✔
204
        auto condition = symbolic::Lt(indvar, this->shape_[i]);
61✔
205
        last_map = &builder.add_map(
61✔
206
            *last_scope,
61✔
207
            indvar,
61✔
208
            condition,
61✔
209
            init,
61✔
210
            update,
61✔
211
            structured_control_flow::ScheduleType_Sequential::create(),
61✔
212
            {},
61✔
213
            block.debug_info()
61✔
214
        );
61✔
215
        last_scope = &last_map->root();
61✔
216

217
        loop_vars.push_back(indvar);
61✔
218
    }
61✔
219

220
    // Linearize subset
221
    symbolic::Expression linear_index = symbolic::zero();
31✔
222
    for (size_t i = 0; i < this->shape_.size(); ++i) {
92✔
223
        linear_index = symbolic::add(symbolic::mul(linear_index, this->shape_[i]), loop_vars[i]);
61✔
224
    }
61✔
225
    if (!this->shape_.empty()) {
31✔
226
        new_subset.push_back(linear_index);
31✔
227
    }
31✔
228

229
    // Add tasklet block
230
    bool success = this->expand_operation(
31✔
231
        builder,
31✔
232
        analysis_manager,
31✔
233
        *last_scope,
31✔
234
        input_node_a.data(),
31✔
235
        input_node_b.data(),
31✔
236
        output_node.data(),
31✔
237
        iedge_a->base_type(),
31✔
238
        iedge_b->base_type(),
31✔
239
        oedge.base_type(),
31✔
240
        new_subset
31✔
241
    );
31✔
242
    if (!success) {
31✔
243
        return false;
×
244
    }
×
245

246
    // Clean up block
247
    builder.remove_memlet(block, *iedge_a);
31✔
248
    builder.remove_memlet(block, *iedge_b);
31✔
249
    builder.remove_memlet(block, oedge);
31✔
250
    builder.remove_node(block, input_node_a);
31✔
251
    builder.remove_node(block, input_node_b);
31✔
252
    builder.remove_node(block, output_node);
31✔
253
    builder.remove_node(block, *this);
31✔
254
    builder.remove_child(parent, index + 1);
31✔
255

256
    return true;
31✔
257
}
31✔
258

259
} // namespace tensor
260
} // namespace math
261
} // 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