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

daisytuner / docc / 26556322966

27 May 2026 03:45PM UTC coverage: 60.869% (-0.02%) from 60.886%
26556322966

push

github

web-flow
Libnode ptr edges (#719)

Migrating SDFGs to treat pointers as inputs to libNodes / Calls as scalars.
A pointer will only appear in an output edge if its actually returned from the function (like malloc).

* Stdlib, Blas and Tensor Matmul nodes were migrated to this new format. Other, currently transitory Tensor Nodes are not yet migrated.
* DOCC version was bumped to incorporate previous docc-llvm versions (up to 0.4.0) that had been counted separately.
! Until all passes consider the use / leak of pointers as uncertainty / hiding potential writes, TensorNodes are declared as general side-effect.
* Lots of utility functions to centralize the creation (and edges) of various libNodes that needed to be changed.
* Fixed & unified docc paths across python and llvm front-ends.
* Skip BlockFusion test that fails to its libNodes currently having side effects
~ Prevent a crash in DotViz when using symbolic offsets into structs
* Removing old ConstProp pass, it is not safe for the new pointer representation and should not be all too critical

961 of 1749 new or added lines in 52 files covered. (54.95%)

87 existing lines in 28 files now uncovered.

35225 of 57870 relevant lines covered (60.87%)

11046.32 hits per line

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

68.92
/sdfg/src/data_flow/tasklet.cpp
1
#include "sdfg/data_flow/tasklet.h"
2

3
#include "sdfg/data_flow/data_flow_graph.h"
4
#include "sdfg/symbolic/symbolic.h"
5

6
namespace sdfg {
7
namespace data_flow {
8

9
Tasklet::Tasklet(
10
    size_t element_id,
11
    const DebugInfo& debug_info,
12
    const graph::Vertex vertex,
13
    DataFlowGraph& parent,
14
    const TaskletCode code,
15
    const std::string& output,
16
    const std::vector<std::string>& inputs
17
)
18
    : CodeNode(element_id, debug_info, vertex, parent, {output}, inputs), code_(code) {};
1,542✔
19

20
void Tasklet::validate(const Function& function) const {
2,975✔
21
    auto& graph = this->get_parent();
2,975✔
22

23
    // Validate: inputs match arity
24
    if (arity(this->code_) != this->inputs_.size()) {
2,975✔
25
        throw InvalidSDFGException(
×
26
            "Tasklet (Code: " + std::to_string(this->code_) + "): Invalid number of inputs. Expected " +
×
27
            std::to_string(arity(this->code_)) + ", got " + std::to_string(this->inputs_.size())
×
28
        );
×
29
    }
×
30

31
    // Validate: inputs match type of operation
32
    for (auto& iedge : graph.in_edges(*this)) {
5,371✔
33
        auto input_type = iedge.result_type(function);
5,371✔
34
        if (is_integer(this->code_) && !types::is_integer(input_type->primitive_type())) {
5,371✔
35
            throw InvalidSDFGException(
×
36
                "Tasklet (Code: " + std::to_string(this->code_) + "): Integer operation with non-integer input type"
×
37
            );
×
38
        }
×
39
        if (is_floating_point(this->code_) && !types::is_floating_point(input_type->primitive_type())) {
5,371✔
40
            throw InvalidSDFGException(
×
41
                "Tasklet (Code: " + std::to_string(this->code_) + "): Floating point operation with integer input type"
×
42
            );
×
43
        }
×
44
    }
5,371✔
45

46
    // Validate: Edges
47
    if (graph.in_degree(*this) != this->inputs_.size()) {
2,975✔
48
        throw InvalidSDFGException(
×
49
            "Tasklet (Code: " + std::to_string(this->code_) +
×
50
            "): Number of input edges does not match number of inputs."
×
51
        );
×
52
    }
×
53
    if (graph.out_degree(*this) != this->outputs_.size()) {
2,975✔
54
        throw InvalidSDFGException(
×
55
            "Tasklet (Code: " + std::to_string(this->code_) +
×
56
            "): Number of output edges does not match number of outputs."
×
57
        );
×
58
    }
×
59
}
2,975✔
60

61
TaskletCode Tasklet::code() const { return this->code_; };
3,727✔
62

63

64
bool Tasklet::is_assign() const { return this->code_ == TaskletCode::assign; }
54✔
65

66
bool Tasklet::is_trivial(const Function& function) const {
1✔
67
    if (!this->is_assign()) {
1✔
68
        return false;
×
69
    }
×
70

71
    auto& graph = this->get_parent();
1✔
72
    auto& iedge = *graph.in_edges(*this).begin();
1✔
73
    auto& oedge = *graph.out_edges(*this).begin();
1✔
74
    auto input_type = iedge.result_type(function);
1✔
75
    auto output_type = oedge.result_type(function);
1✔
76

77
    return input_type->primitive_type() == output_type->primitive_type();
1✔
78
}
1✔
79

80
bool Tasklet::is_cast(const Function& function) const {
10✔
81
    if (!this->is_assign()) {
10✔
82
        return false;
×
83
    }
×
84

85
    auto& graph = this->get_parent();
10✔
86
    auto& iedge = *graph.in_edges(*this).begin();
10✔
87
    auto& oedge = *graph.out_edges(*this).begin();
10✔
88
    auto input_type = iedge.result_type(function);
10✔
89
    auto output_type = oedge.result_type(function);
10✔
90

91
    return input_type->primitive_type() != output_type->primitive_type();
10✔
92
}
10✔
93

94
bool Tasklet::is_zext(const Function& function) const {
13✔
95
    if (!this->is_assign()) {
13✔
96
        return false;
×
97
    }
×
98

99
    auto& graph = this->get_parent();
13✔
100
    auto& iedge = *graph.in_edges(*this).begin();
13✔
101
    auto& oedge = *graph.out_edges(*this).begin();
13✔
102
    auto input_type = iedge.result_type(function);
13✔
103
    auto output_type = oedge.result_type(function);
13✔
104

105
    if (!types::is_unsigned(input_type->primitive_type()) || !types::is_unsigned(output_type->primitive_type())) {
13✔
106
        return false;
7✔
107
    }
7✔
108
    if (types::bit_width(output_type->primitive_type()) <= types::bit_width(input_type->primitive_type())) {
6✔
109
        return false;
3✔
110
    }
3✔
111

112
    return true;
3✔
113
}
6✔
114

115
bool Tasklet::is_sext(const Function& function) const {
1✔
116
    if (!this->is_assign()) {
1✔
117
        return false;
×
118
    }
×
119

120
    auto& graph = this->get_parent();
1✔
121
    auto& iedge = *graph.in_edges(*this).begin();
1✔
122
    auto& oedge = *graph.out_edges(*this).begin();
1✔
123
    auto input_type = iedge.result_type(function);
1✔
124
    auto output_type = oedge.result_type(function);
1✔
125

126
    if (types::is_unsigned(input_type->primitive_type()) || types::is_unsigned(output_type->primitive_type())) {
1✔
127
        return false;
×
128
    }
×
129
    if (types::bit_width(output_type->primitive_type()) <= types::bit_width(input_type->primitive_type())) {
1✔
130
        return false;
×
131
    }
×
132

133
    return true;
1✔
134
}
1✔
135

136
bool Tasklet::is_trunc(const Function& function) const {
13✔
137
    if (!this->is_assign()) {
13✔
138
        return false;
×
139
    }
×
140

141
    auto& graph = this->get_parent();
13✔
142
    auto& iedge = *graph.in_edges(*this).begin();
13✔
143
    auto& oedge = *graph.out_edges(*this).begin();
13✔
144
    auto input_type = iedge.result_type(function);
13✔
145
    auto output_type = oedge.result_type(function);
13✔
146

147
    if (!types::is_integer(input_type->primitive_type()) || !types::is_integer(output_type->primitive_type())) {
13✔
148
        return false;
1✔
149
    }
1✔
150
    if (types::is_unsigned(input_type->primitive_type()) != types::is_unsigned(output_type->primitive_type())) {
12✔
151
        return false;
2✔
152
    }
2✔
153
    if (types::bit_width(output_type->primitive_type()) >= types::bit_width(input_type->primitive_type())) {
10✔
154
        return false;
7✔
155
    }
7✔
156

157
    return true;
3✔
158
}
10✔
159

160
bool Tasklet::is_fptoui(const Function& function) const {
1✔
161
    if (!this->is_assign()) {
1✔
162
        return false;
×
163
    }
×
164

165
    auto& graph = this->get_parent();
1✔
166
    auto& iedge = *graph.in_edges(*this).begin();
1✔
167
    auto& oedge = *graph.out_edges(*this).begin();
1✔
168
    auto input_type = iedge.result_type(function);
1✔
169
    auto output_type = oedge.result_type(function);
1✔
170

171
    if (!types::is_floating_point(input_type->primitive_type()) || !types::is_unsigned(output_type->primitive_type())) {
1✔
172
        return false;
×
173
    }
×
174

175
    return true;
1✔
176
}
1✔
177

178
bool Tasklet::is_fptosi(const Function& function) const {
1✔
179
    if (!this->is_assign()) {
1✔
180
        return false;
×
181
    }
×
182

183
    auto& graph = this->get_parent();
1✔
184
    auto& iedge = *graph.in_edges(*this).begin();
1✔
185
    auto& oedge = *graph.out_edges(*this).begin();
1✔
186
    auto input_type = iedge.result_type(function);
1✔
187
    auto output_type = oedge.result_type(function);
1✔
188

189
    if (!types::is_floating_point(input_type->primitive_type()) || !types::is_signed(output_type->primitive_type())) {
1✔
190
        return false;
×
191
    }
×
192

193
    return true;
1✔
194
}
1✔
195

196
bool Tasklet::is_uitofp(const Function& function) const {
1✔
197
    if (!this->is_assign()) {
1✔
198
        return false;
×
199
    }
×
200

201
    auto& graph = this->get_parent();
1✔
202
    auto& iedge = *graph.in_edges(*this).begin();
1✔
203
    auto& oedge = *graph.out_edges(*this).begin();
1✔
204
    auto input_type = iedge.result_type(function);
1✔
205
    auto output_type = oedge.result_type(function);
1✔
206

207
    if (!types::is_unsigned(input_type->primitive_type()) || !types::is_floating_point(output_type->primitive_type())) {
1✔
208
        return false;
×
209
    }
×
210

211
    return true;
1✔
212
}
1✔
213

214
bool Tasklet::is_sitofp(const Function& function) const {
1✔
215
    if (!this->is_assign()) {
1✔
216
        return false;
×
217
    }
×
218

219
    auto& graph = this->get_parent();
1✔
220
    auto& iedge = *graph.in_edges(*this).begin();
1✔
221
    auto& oedge = *graph.out_edges(*this).begin();
1✔
222
    auto input_type = iedge.result_type(function);
1✔
223
    auto output_type = oedge.result_type(function);
1✔
224

225
    if (!types::is_signed(input_type->primitive_type()) || !types::is_floating_point(output_type->primitive_type())) {
1✔
226
        return false;
×
227
    }
×
228

229
    return true;
1✔
230
}
1✔
231

232
bool Tasklet::is_fpext(const Function& function) const {
1✔
233
    if (!this->is_assign()) {
1✔
234
        return false;
×
235
    }
×
236

237
    auto& graph = this->get_parent();
1✔
238
    auto& iedge = *graph.in_edges(*this).begin();
1✔
239
    auto& oedge = *graph.out_edges(*this).begin();
1✔
240
    auto input_type = iedge.result_type(function);
1✔
241
    auto output_type = oedge.result_type(function);
1✔
242

243
    if (!types::is_floating_point(input_type->primitive_type()) ||
1✔
244
        !types::is_floating_point(output_type->primitive_type())) {
1✔
245
        return false;
×
246
    }
×
247
    if (types::bit_width(output_type->primitive_type()) <= types::bit_width(input_type->primitive_type())) {
1✔
248
        return false;
×
249
    }
×
250

251
    return true;
1✔
252
}
1✔
253

254
bool Tasklet::is_fptrunc(const Function& function) const {
1✔
255
    if (!this->is_assign()) {
1✔
256
        return false;
×
257
    }
×
258

259
    auto& graph = this->get_parent();
1✔
260
    auto& iedge = *graph.in_edges(*this).begin();
1✔
261
    auto& oedge = *graph.out_edges(*this).begin();
1✔
262
    auto input_type = iedge.result_type(function);
1✔
263
    auto output_type = oedge.result_type(function);
1✔
264

265
    if (!types::is_floating_point(input_type->primitive_type()) ||
1✔
266
        !types::is_floating_point(output_type->primitive_type())) {
1✔
267
        return false;
×
268
    }
×
269
    if (types::bit_width(output_type->primitive_type()) >= types::bit_width(input_type->primitive_type())) {
1✔
270
        return false;
×
271
    }
×
272

273
    return true;
1✔
274
}
1✔
275

276
const std::string& Tasklet::output() const { return this->outputs_[0]; };
104✔
277

278
std::unique_ptr<DataFlowNode> Tasklet::clone(size_t element_id, const graph::Vertex vertex, DataFlowGraph& parent)
279
    const {
26✔
280
    return std::unique_ptr<Tasklet>(
26✔
281
        new Tasklet(element_id, this->debug_info_, vertex, parent, this->code_, this->outputs_.at(0), this->inputs_)
26✔
282
    );
26✔
283
};
26✔
284

285
void Tasklet::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {}
212✔
286

287
EdgeRemoveOption Tasklet::can_remove_out_edge(const data_flow::DataFlowGraph& graph, const Memlet* memlet) const {
7✔
288
    if (graph.out_edges_for_connector(*this, memlet->src_conn()).size() > 1) {
7✔
289
        return EdgeRemoveOption::Trivially;
×
290
    } else {
7✔
291
        // trick to allow removal of Tasklets, without having general mark-and-sweep logic to checkl tha that all
292
        // outputs are
293
        return EdgeRemoveOption::RemoveNodeAfter;
7✔
294
    }
7✔
295
}
7✔
296

NEW
297
EdgeRemoveOption Tasklet::can_remove_in_edge(const data_flow::DataFlowGraph& graph, const Memlet* memlet) const {
×
NEW
298
    return EdgeRemoveOption::NotRemovable;
×
NEW
299
}
×
300

301
} // namespace data_flow
302
} // namespace sdfg
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc