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

daisytuner / docc / 23848280014

01 Apr 2026 12:21PM UTC coverage: 64.42% (-0.07%) from 64.49%
23848280014

Pull #624

github

web-flow
Merge 2e8bcfaf8 into 53580ad0f
Pull Request #624: Skip redundant invalidates on perfect loop distribution

43 of 45 new or added lines in 2 files covered. (95.56%)

286 existing lines in 8 files now uncovered.

28812 of 44725 relevant lines covered (64.42%)

435.84 hits per line

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

13.86
/sdfg/src/data_flow/library_nodes/math/cmath/cmath_node.cpp
1
#include "sdfg/data_flow/library_nodes/math/cmath/cmath_node.h"
2
#include "sdfg/symbolic/symbolic.h"
3

4
#include <string>
5
#include <unordered_map>
6

7
#include "sdfg/types/utils.h"
8

9
namespace sdfg {
10
namespace math {
11
namespace cmath {
12

13
CMathFunction string_to_cmath_function(const std::string& name) {
×
14
    static const std::unordered_map<std::string, CMathFunction> function_map = {
×
15
        {"sin", CMathFunction::sin},
×
16
        {"sinf", CMathFunction::sin},
×
17
        {"sinl", CMathFunction::sin},
×
18
        {"cos", CMathFunction::cos},
×
19
        {"cosf", CMathFunction::cos},
×
20
        {"cosl", CMathFunction::cos},
×
21
        {"tan", CMathFunction::tan},
×
22
        {"tanf", CMathFunction::tan},
×
23
        {"tanl", CMathFunction::tan},
×
24
        {"asin", CMathFunction::asin},
×
25
        {"asinf", CMathFunction::asin},
×
26
        {"asinl", CMathFunction::asin},
×
27
        {"acos", CMathFunction::acos},
×
28
        {"acosf", CMathFunction::acos},
×
29
        {"acosl", CMathFunction::acos},
×
30
        {"atan", CMathFunction::atan},
×
31
        {"atanf", CMathFunction::atan},
×
32
        {"atanl", CMathFunction::atan},
×
33
        {"atan2", CMathFunction::atan2},
×
34
        {"atan2f", CMathFunction::atan2},
×
35
        {"atan2l", CMathFunction::atan2},
×
36
        {"sinh", CMathFunction::sinh},
×
37
        {"sinhf", CMathFunction::sinh},
×
38
        {"sinhl", CMathFunction::sinh},
×
39
        {"cosh", CMathFunction::cosh},
×
40
        {"coshf", CMathFunction::cosh},
×
41
        {"coshl", CMathFunction::cosh},
×
42
        {"tanh", CMathFunction::tanh},
×
43
        {"tanhf", CMathFunction::tanh},
×
44
        {"tanhl", CMathFunction::tanh},
×
45
        {"asinh", CMathFunction::asinh},
×
46
        {"asinhf", CMathFunction::asinh},
×
47
        {"asinhl", CMathFunction::asinh},
×
48
        {"acosh", CMathFunction::acosh},
×
49
        {"acoshf", CMathFunction::acosh},
×
50
        {"acoshl", CMathFunction::acosh},
×
51
        {"atanh", CMathFunction::atanh},
×
52
        {"atanhf", CMathFunction::atanh},
×
53
        {"atanhl", CMathFunction::atanh},
×
54
        {"exp", CMathFunction::exp},
×
55
        {"expf", CMathFunction::exp},
×
56
        {"expl", CMathFunction::exp},
×
57
        {"exp2", CMathFunction::exp2},
×
58
        {"exp2f", CMathFunction::exp2},
×
59
        {"exp2l", CMathFunction::exp2},
×
60
        {"exp10", CMathFunction::exp10},
×
61
        {"exp10f", CMathFunction::exp10},
×
62
        {"exp10l", CMathFunction::exp10},
×
63
        {"expm1", CMathFunction::expm1},
×
64
        {"expm1f", CMathFunction::expm1},
×
65
        {"expm1l", CMathFunction::expm1},
×
66
        {"log", CMathFunction::log},
×
67
        {"logf", CMathFunction::log},
×
68
        {"logl", CMathFunction::log},
×
69
        {"log10", CMathFunction::log10},
×
70
        {"log10f", CMathFunction::log10},
×
71
        {"log10l", CMathFunction::log10},
×
72
        {"log2", CMathFunction::log2},
×
73
        {"log2f", CMathFunction::log2},
×
74
        {"log2l", CMathFunction::log2},
×
75
        {"log1p", CMathFunction::log1p},
×
76
        {"log1pf", CMathFunction::log1p},
×
77
        {"log1pl", CMathFunction::log1p},
×
78
        {"pow", CMathFunction::pow},
×
79
        {"powf", CMathFunction::pow},
×
80
        {"powl", CMathFunction::pow},
×
81
        {"sqrt", CMathFunction::sqrt},
×
82
        {"sqrtf", CMathFunction::sqrt},
×
83
        {"sqrtl", CMathFunction::sqrt},
×
84
        {"cbrt", CMathFunction::cbrt},
×
85
        {"cbrtf", CMathFunction::cbrt},
×
86
        {"cbrtl", CMathFunction::cbrt},
×
87
        {"hypot", CMathFunction::hypot},
×
88
        {"hypotf", CMathFunction::hypot},
×
89
        {"hypotl", CMathFunction::hypot},
×
90
        {"erf", CMathFunction::erf},
×
91
        {"erff", CMathFunction::erf},
×
92
        {"erfl", CMathFunction::erf},
×
93
        {"erfc", CMathFunction::erfc},
×
94
        {"erfcf", CMathFunction::erfc},
×
95
        {"erfcl", CMathFunction::erfc},
×
96
        {"tgamma", CMathFunction::tgamma},
×
97
        {"tgammaf", CMathFunction::tgamma},
×
98
        {"tgammal", CMathFunction::tgamma},
×
99
        {"lgamma", CMathFunction::lgamma},
×
100
        {"lgammaf", CMathFunction::lgamma},
×
101
        {"lgammal", CMathFunction::lgamma},
×
102
        {"fabs", CMathFunction::fabs},
×
103
        {"fabsf", CMathFunction::fabs},
×
104
        {"fabsl", CMathFunction::fabs},
×
105
        {"ceil", CMathFunction::ceil},
×
106
        {"ceilf", CMathFunction::ceil},
×
107
        {"ceill", CMathFunction::ceil},
×
108
        {"floor", CMathFunction::floor},
×
109
        {"floorf", CMathFunction::floor},
×
110
        {"floorl", CMathFunction::floor},
×
111
        {"trunc", CMathFunction::trunc},
×
112
        {"truncf", CMathFunction::trunc},
×
113
        {"truncl", CMathFunction::trunc},
×
114
        {"round", CMathFunction::round},
×
115
        {"roundf", CMathFunction::round},
×
116
        {"roundl", CMathFunction::round},
×
117
        {"lround", CMathFunction::lround},
×
118
        {"lroundf", CMathFunction::lround},
×
119
        {"lroundl", CMathFunction::lround},
×
120
        {"llround", CMathFunction::llround},
×
121
        {"llroundf", CMathFunction::llround},
×
122
        {"llroundl", CMathFunction::llround},
×
123
        {"roundeven", CMathFunction::roundeven},
×
124
        {"roundevenf", CMathFunction::roundeven},
×
125
        {"roundevenl", CMathFunction::roundeven},
×
126
        {"nearbyint", CMathFunction::nearbyint},
×
127
        {"nearbyintf", CMathFunction::nearbyint},
×
128
        {"nearbyintl", CMathFunction::nearbyint},
×
129
        {"rint", CMathFunction::rint},
×
130
        {"rintf", CMathFunction::rint},
×
131
        {"rintl", CMathFunction::rint},
×
132
        {"lrint", CMathFunction::lrint},
×
133
        {"lrintf", CMathFunction::lrint},
×
134
        {"lrintl", CMathFunction::lrint},
×
135
        {"llrint", CMathFunction::llrint},
×
136
        {"llrintf", CMathFunction::llrint},
×
137
        {"llrintl", CMathFunction::llrint},
×
138
        {"fmod", CMathFunction::fmod},
×
139
        {"fmodf", CMathFunction::fmod},
×
140
        {"fmodl", CMathFunction::fmod},
×
141
        {"remainder", CMathFunction::remainder},
×
142
        {"remainderf", CMathFunction::remainder},
×
143
        {"remainderl", CMathFunction::remainder},
×
144
        {"frexp", CMathFunction::frexp},
×
145
        {"frexpf", CMathFunction::frexp},
×
146
        {"frexpl", CMathFunction::frexp},
×
147
        {"ldexp", CMathFunction::ldexp},
×
148
        {"ldexpf", CMathFunction::ldexp},
×
149
        {"ldexpl", CMathFunction::ldexp},
×
150
        {"modf", CMathFunction::modf},
×
151
        {"modff", CMathFunction::modf},
×
152
        {"modfl", CMathFunction::modf},
×
153
        {"scalbn", CMathFunction::scalbn},
×
154
        {"scalbnf", CMathFunction::scalbn},
×
155
        {"scalbnl", CMathFunction::scalbn},
×
156
        {"scalbln", CMathFunction::scalbln},
×
157
        {"scalblnf", CMathFunction::scalbln},
×
158
        {"scalblnl", CMathFunction::scalbln},
×
159
        {"ilogb", CMathFunction::ilogb},
×
160
        {"ilogbf", CMathFunction::ilogb},
×
161
        {"ilogbl", CMathFunction::ilogb},
×
162
        {"logb", CMathFunction::logb},
×
163
        {"logbf", CMathFunction::logb},
×
164
        {"logbl", CMathFunction::logb},
×
165
        {"nextafter", CMathFunction::nextafter},
×
166
        {"nextafterf", CMathFunction::nextafter},
×
167
        {"nextafterl", CMathFunction::nextafter},
×
168
        {"nexttoward", CMathFunction::nexttoward},
×
169
        {"nexttowardf", CMathFunction::nexttoward},
×
170
        {"nexttowardl", CMathFunction::nexttoward},
×
171
        {"copysign", CMathFunction::copysign},
×
172
        {"copysignf", CMathFunction::copysign},
×
173
        {"copysignl", CMathFunction::copysign},
×
174
        {"fmax", CMathFunction::fmax},
×
175
        {"fmaxf", CMathFunction::fmax},
×
176
        {"fmaxl", CMathFunction::fmax},
×
177
        {"fmin", CMathFunction::fmin},
×
178
        {"fminf", CMathFunction::fmin},
×
179
        {"fminl", CMathFunction::fmin},
×
180
        {"fdim", CMathFunction::fdim},
×
181
        {"fdimf", CMathFunction::fdim},
×
182
        {"fdiml", CMathFunction::fdim},
×
183
        {"fma", CMathFunction::fma},
×
184
        {"fmaf", CMathFunction::fma},
×
185
        {"fmal", CMathFunction::fma},
×
186
    };
×
187

188
    auto it = function_map.find(name);
×
189
    if (it != function_map.end()) {
×
190
        return it->second;
×
191
    }
×
192

193
    throw std::runtime_error("Unknown CMath function: " + name);
×
194
}
×
195

196
CMathNode::CMathNode(
197
    size_t element_id,
198
    const DebugInfo& debug_info,
199
    const graph::Vertex vertex,
200
    data_flow::DataFlowGraph& parent,
201
    CMathFunction function,
202
    types::PrimitiveType primitive_type
203
)
204
    : MathNode(
357✔
205
          element_id, debug_info, vertex, parent, LibraryNodeType_CMath, {"_out"}, {}, data_flow::ImplementationType_NONE
357✔
206
      ),
357✔
207
      function_(function), primitive_type_(primitive_type) {
357✔
208
    for (size_t i = 0; i < cmath_function_to_arity(function); i++) {
817✔
209
        this->inputs_.push_back("_in" + std::to_string(i + 1));
460✔
210
    }
460✔
211
}
357✔
212

213
CMathFunction CMathNode::function() const { return this->function_; }
240✔
214

215
types::PrimitiveType CMathNode::primitive_type() const { return this->primitive_type_; }
12✔
216

217
std::string CMathNode::name() const { return get_cmath_intrinsic_name(this->function_, this->primitive_type_); }
3✔
218

219
symbolic::SymbolSet CMathNode::symbols() const { return {}; }
14✔
220

221
void CMathNode::replace(const symbolic::Expression old_expression, const symbolic::Expression new_expression) {
×
222
    return;
×
223
}
×
224

225
void CMathNode::validate(const Function& function) const {
293✔
226
    MathNode::validate(function);
293✔
227

228
    if (!types::is_floating_point(this->primitive_type_)) {
293✔
229
        throw InvalidSDFGException("CMathNode: Primitive type must be a floating point type");
1✔
230
    }
1✔
231

232
    auto& dataflow = this->get_parent();
292✔
233
    if (this->inputs_.size() != dataflow.in_degree(*this)) {
292✔
234
        throw InvalidSDFGException("CMathNode: Mismatch between number of inputs and in-degree of the node");
×
235
    }
×
236
    if (this->outputs_.size() != dataflow.out_degree(*this)) {
292✔
237
        throw InvalidSDFGException("CMathNode: Mismatch between number of outputs and out-degree of the node");
×
238
    }
×
239
    for (const auto& iedge : dataflow.in_edges(*this)) {
365✔
240
        auto inferred_type = types::infer_type(function, iedge.base_type(), iedge.subset());
365✔
241
        auto type_id = inferred_type->type_id();
365✔
242
        bool type_ok = false;
365✔
243
        if (type_id == types::TypeID::Scalar) {
365✔
244
            type_ok = true;
365✔
245
        } else if (type_id == types::TypeID::Tensor) {
365✔
246
            auto& tensor = dynamic_cast<types::Tensor&>(*inferred_type);
×
247
            if (tensor.is_scalar()) {
×
248
                type_ok = true;
×
249
            }
×
250
        }
×
251
        if (!type_ok) {
365✔
252
            throw InvalidSDFGException(
×
253
                "CMathNode: Input type on " + std::to_string(this->element_id()) + ":" + iedge.dst_conn() +
×
254
                " must be scalar, but was " + std::to_string(static_cast<int>(type_id))
×
255
            );
×
256
        }
×
257
        auto& scalar_type = static_cast<const types::Scalar&>(*inferred_type);
365✔
258
        if (scalar_type.primitive_type() != this->primitive_type_) {
365✔
259
            std::string input_primitive_type_str = types::primitive_type_to_string(scalar_type.primitive_type());
×
260
            std::string node_primitive_type_str = types::primitive_type_to_string(this->primitive_type_);
×
261
            throw InvalidSDFGException(
×
262
                "CMathNode: Input primitive type " + input_primitive_type_str + " does not match node primitive type " +
×
263
                node_primitive_type_str + " for function " + cmath_function_to_stem(this->function_)
×
264
            );
×
265
        }
×
266
    }
365✔
267
    for (const auto& oedge : dataflow.out_edges(*this)) {
292✔
268
        auto inferred_type = types::infer_type(function, oedge.base_type(), oedge.subset());
292✔
269
        auto type_id = inferred_type->type_id();
292✔
270
        bool type_ok = false;
292✔
271
        if (type_id == types::TypeID::Scalar) {
292✔
272
            type_ok = true;
292✔
273
        } else if (type_id == types::TypeID::Tensor) {
292✔
274
            auto& tensor = dynamic_cast<types::Tensor&>(*inferred_type);
×
275
            if (tensor.is_scalar()) {
×
276
                type_ok = true;
×
277
            }
×
278
        }
×
279
        if (!type_ok) {
292✔
280
            throw InvalidSDFGException(
×
281
                "Output: Input type in " + std::to_string(this->element_id()) + " must be scalar, but was " +
×
282
                std::to_string(static_cast<int>(type_id))
×
283
            );
×
284
        }
×
285
        auto& scalar_type = static_cast<const types::Scalar&>(*inferred_type);
292✔
286
        if (this->function_ == CMathFunction::lrint || this->function_ == CMathFunction::llrint ||
292✔
287
            this->function_ == CMathFunction::lround || this->function_ == CMathFunction::llround) {
292✔
288
            if (!types::is_integer(scalar_type.primitive_type())) {
16✔
289
                std::string output_primitive_type_str = types::primitive_type_to_string(scalar_type.primitive_type());
×
290
                throw InvalidSDFGException(
×
291
                    "CMathNode: Output primitive type must be an integer type for lrint, llrint, lround, llround "
×
292
                    "functions. Found: " +
×
293
                    output_primitive_type_str
×
294
                );
×
295
            }
×
296
        } else if (scalar_type.primitive_type() != this->primitive_type_) {
276✔
297
            std::string output_primitive_type_str = types::primitive_type_to_string(scalar_type.primitive_type());
×
298
            std::string node_primitive_type_str = types::primitive_type_to_string(this->primitive_type_);
×
299
            throw InvalidSDFGException(
×
300
                "CMathNode: Output primitive type " + output_primitive_type_str +
×
301
                " does not match node primitive type " + node_primitive_type_str
×
302
            );
×
303
        }
×
304
    }
292✔
305
}
292✔
306

307
std::unique_ptr<data_flow::DataFlowNode> CMathNode::
308
    clone(size_t element_id, const graph::Vertex vertex, data_flow::DataFlowGraph& parent) const {
×
309
    return std::unique_ptr<
×
310
        CMathNode>(new CMathNode(element_id, this->debug_info(), vertex, parent, this->function_, this->primitive_type_)
×
311
    );
×
312
}
×
313

314
symbolic::Expression CMathNode::flop() const { return symbolic::one(); }
1✔
315

316
std::string CMathNode::toStr() const {
×
317
    return LibraryNode::toStr() + "(" + get_cmath_intrinsic_name(this->function_, this->primitive_type_) + ")";
×
318
}
×
319

320
nlohmann::json CMathNodeSerializer::serialize(const data_flow::LibraryNode& library_node) {
×
321
    const CMathNode& node = static_cast<const CMathNode&>(library_node);
×
322
    nlohmann::json j;
×
323

324
    serializer::JSONSerializer serializer;
×
UNCOV
325
    j["code"] = node.code().value();
×
326
    j["name"] = node.name();
×
327
    j["function_stem"] = cmath_function_to_stem(node.function());
×
UNCOV
328
    j["primitive_type"] = static_cast<int>(node.primitive_type());
×
329

UNCOV
330
    return j;
×
331
}
×
332

333
data_flow::LibraryNode& CMathNodeSerializer::deserialize(
334
    const nlohmann::json& j, builder::StructuredSDFGBuilder& builder, structured_control_flow::Block& parent
335
) {
×
336
    // Assertions for required fields
337
    assert(j.contains("element_id"));
×
UNCOV
338
    assert(j.contains("code"));
×
339
    assert(j.contains("debug_info"));
×
340

341
    auto code = j["code"].get<std::string>();
×
342
    // Backward compatibility
UNCOV
343
    if (code != LibraryNodeType_CMath.value() && code != LibraryNodeType_CMath_Deprecated.value()) {
×
344
        throw std::runtime_error("Invalid library node code");
×
345
    }
×
346

347
    // Extract debug info using JSONSerializer
348
    sdfg::serializer::JSONSerializer serializer;
×
349
    DebugInfo debug_info = serializer.json_to_debug_info(j["debug_info"]);
×
350

351
    // Try new format first (with function_stem and primitive_type)
UNCOV
352
    CMathFunction function;
×
353
    types::PrimitiveType prim_type;
×
354

355
    if (j.contains("function_stem") && j.contains("primitive_type")) {
×
356
        // New format
UNCOV
357
        auto stem = j["function_stem"].get<std::string>();
×
358
        function = string_to_cmath_function(stem);
×
359
        prim_type = static_cast<types::PrimitiveType>(j["primitive_type"].get<int>());
×
UNCOV
360
    } else {
×
361
        // Backward compatibility: old format with just "name"
362
        auto name = j["name"].get<std::string>();
×
363
        function = string_to_cmath_function(name);
×
364
        // Infer primitive type from the suffix
365
        if (name.back() == 'f') {
×
366
            prim_type = types::PrimitiveType::Float;
×
367
        } else if (name.back() == 'l') {
×
368
            prim_type = types::PrimitiveType::X86_FP80; // Assuming long double
×
UNCOV
369
        } else {
×
370
            prim_type = types::PrimitiveType::Double;
×
371
        }
×
UNCOV
372
    }
×
373

UNCOV
374
    return builder.add_library_node<CMathNode>(parent, debug_info, function, prim_type);
×
UNCOV
375
}
×
376

377
CMathNodeDispatcher::CMathNodeDispatcher(
378
    codegen::LanguageExtension& language_extension,
379
    const Function& function,
380
    const data_flow::DataFlowGraph& data_flow_graph,
381
    const CMathNode& node
382
)
UNCOV
383
    : codegen::LibraryNodeDispatcher(language_extension, function, data_flow_graph, node) {}
×
384

385
void CMathNodeDispatcher::dispatch_code(
386
    codegen::PrettyPrinter& stream,
387
    codegen::PrettyPrinter& globals_stream,
388
    codegen::CodeSnippetFactory& library_snippet_factory
389
) {
×
UNCOV
390
    stream << "{" << std::endl;
×
391
    stream.setIndent(stream.indent() + 4);
×
392

393
    auto& node = static_cast<const CMathNode&>(this->node_);
×
394

395
    stream << node.outputs().at(0) << " = ";
×
396
    stream << node.name() << "(";
×
397
    for (size_t i = 0; i < node.inputs().size(); i++) {
×
398
        stream << node.inputs().at(i);
×
399
        if (i < node.inputs().size() - 1) {
×
UNCOV
400
            stream << ", ";
×
401
        }
×
402
    }
×
403
    stream << ");" << std::endl;
×
404

UNCOV
405
    stream.setIndent(stream.indent() - 4);
×
UNCOV
406
    stream << "}" << std::endl;
×
UNCOV
407
}
×
408

409
} // namespace cmath
410
} // namespace math
411
} // 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