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

daisytuner / docc / 28158800507

25 Jun 2026 08:57AM UTC coverage: 61.644% (+0.06%) from 61.582%
28158800507

push

github

web-flow
MapFusionByDomain (#771)

 + New Map fusion caches data about iteration domain and map candidates
 + only matches up iteration domain exactly, per loop level.
 + Can support fusing non-leaf stacks of loops (stack ends where the shallower stack stops being perfectly nested & parallel)
 + new Element::replace for bulk replacements
 + New PatternMatcher visitor supports descending into replaced or modified nodes to allow for single-pass nested loop fusings
 + LoopAnalysis can now be kept up-to-date with changes done by Map-fusion
 + unit tests for the updating of LoopAnalysis
 * updated LoopAnalysis to be easier to keep up-to-date with changes. LoopTree is no longer ordered, if you want to iterate in pre-order, use the specific method for that
 + convenience StructuredSDFGBuilder.remove_from_parent()
 + RedundantLoadElim pass to skip reading from memory locations that have just been written (same block). Fusing no longer needs to do this
     RedundantLoadElimination does a simple check for other writes to the same structure. Can skip writes if redundant or not modify, if their are writes to different indices
* Updated verifiers to match new fusion
~ moved verifier checks behind correctness checks in npbench harness. Its more critical if we do not even get the expected results
* Added MapFusionByDomain also to loop-norm stage (currently inactive, causes more kernels that currently cannot be safely offloaded to CUDA.
---------

Co-authored-by: Lukas Truemper <lukas.truemper@outlook.de>

771 of 1186 new or added lines in 55 files covered. (65.01%)

6 existing lines in 6 files now uncovered.

38302 of 62134 relevant lines covered (61.64%)

987.24 hits per line

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

13.26
/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(
324✔
205
          element_id, debug_info, vertex, parent, LibraryNodeType_CMath, {"_out"}, {}, data_flow::ImplementationType_NONE
324✔
206
      ),
324✔
207
      function_(function), primitive_type_(primitive_type) {
324✔
208
    for (size_t i = 0; i < cmath_function_to_arity(function); i++) {
739✔
209
        this->inputs_.push_back("_in" + std::to_string(i + 1));
415✔
210
    }
415✔
211
}
324✔
212

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

215
types::PrimitiveType CMathNode::primitive_type() const { return this->primitive_type_; }
×
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 {}; }
9✔
220

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

NEW
225
void CMathNode::replace(const symbolic::ExpressionMapping& replacements) { return; }
×
226

227
void CMathNode::validate(const Function& function) const {
292✔
228
    MathNode::validate(function);
292✔
229

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

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

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

316
symbolic::Expression CMathNode::flop() const { return symbolic::one(); }
1✔
317

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

322
data_flow::EdgeRemoveOption CMathNode::
323
    can_remove_out_edge(const data_flow::DataFlowGraph& graph, const data_flow::Memlet* memlet) const {
×
324
    if (graph.out_edges_for_connector(*this, memlet->src_conn()).size() > 1) {
×
325
        return data_flow::EdgeRemoveOption::Trivially;
×
326
    } else {
×
327
        // trick to allow removal of Tasklets, without having general mark-and-sweep logic to checkl tha that all
328
        // outputs are
329
        return data_flow::EdgeRemoveOption::RemoveNodeAfter;
×
330
    }
×
331
}
×
332

333
nlohmann::json CMathNodeSerializer::serialize(const data_flow::LibraryNode& library_node) {
×
334
    const CMathNode& node = static_cast<const CMathNode&>(library_node);
×
335
    nlohmann::json j;
×
336

337
    serializer::JSONSerializer serializer;
×
338
    j["code"] = node.code().value();
×
339
    j["name"] = node.name();
×
340
    j["function_stem"] = cmath_function_to_stem(node.function());
×
341
    j["primitive_type"] = static_cast<int>(node.primitive_type());
×
342

343
    return j;
×
344
}
×
345

346
data_flow::LibraryNode& CMathNodeSerializer::deserialize(
347
    const nlohmann::json& j, builder::StructuredSDFGBuilder& builder, structured_control_flow::Block& parent
348
) {
×
349
    // Assertions for required fields
350
    assert(j.contains("element_id"));
×
351
    assert(j.contains("code"));
×
352
    assert(j.contains("debug_info"));
×
353

354
    auto code = j["code"].get<std::string>();
×
355
    // Backward compatibility
356
    if (code != LibraryNodeType_CMath.value() && code != LibraryNodeType_CMath_Deprecated.value()) {
×
357
        throw std::runtime_error("Invalid library node code");
×
358
    }
×
359

360
    // Extract debug info using JSONSerializer
361
    sdfg::serializer::JSONSerializer serializer;
×
362
    DebugInfo debug_info = serializer.json_to_debug_info(j["debug_info"]);
×
363

364
    // Try new format first (with function_stem and primitive_type)
365
    CMathFunction function;
×
366
    types::PrimitiveType prim_type;
×
367

368
    if (j.contains("function_stem") && j.contains("primitive_type")) {
×
369
        // New format
370
        auto stem = j["function_stem"].get<std::string>();
×
371
        function = string_to_cmath_function(stem);
×
372
        prim_type = static_cast<types::PrimitiveType>(j["primitive_type"].get<int>());
×
373
    } else {
×
374
        // Backward compatibility: old format with just "name"
375
        auto name = j["name"].get<std::string>();
×
376
        function = string_to_cmath_function(name);
×
377
        // Infer primitive type from the suffix
378
        if (name.back() == 'f') {
×
379
            prim_type = types::PrimitiveType::Float;
×
380
        } else if (name.back() == 'l') {
×
381
            prim_type = types::PrimitiveType::X86_FP80; // Assuming long double
×
382
        } else {
×
383
            prim_type = types::PrimitiveType::Double;
×
384
        }
×
385
    }
×
386

387
    return builder.add_library_node<CMathNode>(parent, debug_info, function, prim_type);
×
388
}
×
389

390
CMathNodeDispatcher::CMathNodeDispatcher(
391
    codegen::LanguageExtension& language_extension,
392
    const Function& function,
393
    const data_flow::DataFlowGraph& data_flow_graph,
394
    const CMathNode& node
395
)
396
    : codegen::LibraryNodeDispatcher(language_extension, function, data_flow_graph, node) {}
×
397

398
void CMathNodeDispatcher::dispatch_code(
399
    codegen::PrettyPrinter& stream,
400
    codegen::PrettyPrinter& globals_stream,
401
    codegen::CodeSnippetFactory& library_snippet_factory
402
) {
×
403
    stream << "{" << std::endl;
×
404
    stream.setIndent(stream.indent() + 4);
×
405

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

408
    stream << node.outputs().at(0) << " = ";
×
409
    stream << node.name() << "(";
×
410
    for (size_t i = 0; i < node.inputs().size(); i++) {
×
411
        stream << node.inputs().at(i);
×
412
        if (i < node.inputs().size() - 1) {
×
413
            stream << ", ";
×
414
        }
×
415
    }
×
416
    stream << ");" << std::endl;
×
417

418
    stream.setIndent(stream.indent() - 4);
×
419
    stream << "}" << std::endl;
×
420
}
×
421

422
} // namespace cmath
423
} // namespace math
424
} // 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