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

daisytuner / sdfglib / 18318176242

07 Oct 2025 03:42PM UTC coverage: 61.593% (+0.5%) from 61.066%
18318176242

Pull #262

github

web-flow
Merge 98864a558 into 82460a9ec
Pull Request #262: Tasklets, Intrinsics and Library Nodes

84 of 418 new or added lines in 29 files covered. (20.1%)

153 existing lines in 17 files now uncovered.

8979 of 14578 relevant lines covered (61.59%)

103.69 hits per line

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

41.4
/src/codegen/language_extensions/c_language_extension.cpp
1
#include "sdfg/codegen/language_extensions/c_language_extension.h"
2

3
#include <cstddef>
4
#include <string>
5

6
#include "sdfg/codegen/utils.h"
7
#include "sdfg/data_flow/tasklet.h"
8
#include "sdfg/exceptions.h"
9
#include "sdfg/types/type.h"
10

11
namespace sdfg {
12
namespace codegen {
13

14
std::string CLanguageExtension::primitive_type(const types::PrimitiveType prim_type) {
35✔
15
    switch (prim_type) {
35✔
16
        case types::PrimitiveType::Void:
17
            return "void";
2✔
18
        case types::PrimitiveType::Bool:
19
            return "bool";
1✔
20
        case types::PrimitiveType::Int8:
21
            return "signed char";
1✔
22
        case types::PrimitiveType::Int16:
23
            return "short";
1✔
24
        case types::PrimitiveType::Int32:
25
            return "int";
17✔
26
        case types::PrimitiveType::Int64:
27
            return "long long";
2✔
28
        case types::PrimitiveType::Int128:
29
            return "__int128";
×
30
        case types::PrimitiveType::UInt8:
31
            return "char";
3✔
32
        case types::PrimitiveType::UInt16:
33
            return "unsigned short";
1✔
34
        case types::PrimitiveType::UInt32:
35
            return "unsigned int";
1✔
36
        case types::PrimitiveType::UInt64:
37
            return "unsigned long long";
1✔
38
        case types::PrimitiveType::UInt128:
39
            return "unsigned __int128";
×
40
        case types::PrimitiveType::Half:
41
            return "__fp16";
×
42
        case types::PrimitiveType::BFloat:
43
            return "__bf16";
×
44
        case types::PrimitiveType::Float:
45
            return "float";
4✔
46
        case types::PrimitiveType::Double:
47
            return "double";
1✔
48
        case types::PrimitiveType::X86_FP80:
49
            return "long double";
×
50
        case types::PrimitiveType::FP128:
51
            return "__float128";
×
52
        case types::PrimitiveType::PPC_FP128:
53
            return "__float128";
×
54
    }
55

56
    throw std::runtime_error("Unknown primitive type");
×
57
};
35✔
58

59
std::string CLanguageExtension::
60
    declaration(const std::string& name, const types::IType& type, bool use_initializer, bool use_alignment) {
38✔
61
    std::stringstream val;
38✔
62

63
    if (auto scalar_type = dynamic_cast<const types::Scalar*>(&type)) {
38✔
64
        val << primitive_type(scalar_type->primitive_type());
20✔
65
        val << " ";
20✔
66
        val << name;
20✔
67
    } else if (auto array_type = dynamic_cast<const types::Array*>(&type)) {
38✔
68
        auto& element_type = array_type->element_type();
3✔
69
        val << declaration(name + "[" + this->expression(array_type->num_elements()) + "]", element_type);
3✔
70
    } else if (auto pointer_type = dynamic_cast<const types::Pointer*>(&type)) {
18✔
71
        if (pointer_type->has_pointee_type()) {
11✔
72
            const types::IType& pointee = pointer_type->pointee_type();
10✔
73

74
            const bool pointee_is_function_or_array = dynamic_cast<const types::Function*>(&pointee) ||
20✔
75
                                                      dynamic_cast<const types::Array*>(&pointee);
10✔
76

77
            // Parenthesise *only* when it is needed to bind tighter than [] or ()
78
            std::string decorated = pointee_is_function_or_array ? "(*" + name + ")" : "*" + name;
10✔
79

80
            val << declaration(decorated, pointee);
10✔
81
        } else {
10✔
82
            val << "void*";
1✔
83
            val << " " << name;
1✔
84
        }
85
    } else if (auto ref_type = dynamic_cast<const Reference*>(&type)) {
15✔
86
        val << declaration("&" + name, ref_type->reference_type());
×
87
    } else if (auto structure_type = dynamic_cast<const types::Structure*>(&type)) {
4✔
88
        val << structure_type->name();
4✔
89
        val << " ";
4✔
90
        val << name;
4✔
91
    } else if (auto function_type = dynamic_cast<const types::Function*>(&type)) {
4✔
92
        std::stringstream params;
×
93
        for (size_t i = 0; i < function_type->num_params(); ++i) {
×
94
            params << declaration("", function_type->param_type(symbolic::integer(i)));
×
95
            if (i + 1 < function_type->num_params()) params << ", ";
×
96
        }
×
97
        if (function_type->is_var_arg()) {
×
98
            // ISO C forbids empty parameter lists before ...
99
            if (function_type->num_params() > 0) {
×
100
                params << ", ";
×
101
                params << "...";
×
102
            }
×
103
        }
×
104

105
        const std::string fun_name = name + "(" + params.str() + ")";
×
106
        val << declaration(fun_name, function_type->return_type());
×
107
    } else {
×
108
        throw std::runtime_error("Unknown declaration type");
×
109
    }
110

111
    if (use_alignment && type.alignment() > 0) {
38✔
112
        val << " __attribute__((aligned(" << type.alignment() << ")))";
×
113
    }
×
114

115
    if (use_initializer && !type.initializer().empty()) {
38✔
116
        val << " = " << type.initializer();
×
117
    }
×
118

119
    return val.str();
38✔
120
};
38✔
121

122
std::string CLanguageExtension::type_cast(const std::string& name, const types::IType& type) {
5✔
123
    std::stringstream val;
5✔
124

125
    val << "(";
5✔
126
    val << declaration("", type);
5✔
127
    val << ") ";
5✔
128
    val << name;
5✔
129

130
    return val.str();
5✔
131
};
5✔
132

133
std::string CLanguageExtension::subset(const Function& function, const types::IType& type, const data_flow::Subset& sub) {
15✔
134
    if (sub.empty()) {
15✔
135
        return "";
12✔
136
    }
137

138
    if (dynamic_cast<const types::Scalar*>(&type)) {
3✔
139
        return "";
×
140
    } else if (auto array_type = dynamic_cast<const types::Array*>(&type)) {
3✔
141
        std::string subset_str = "[" + this->expression(sub.at(0)) + "]";
1✔
142

143
        if (sub.size() > 1) {
1✔
144
            data_flow::Subset element_subset(sub.begin() + 1, sub.end());
×
145
            auto& element_type = array_type->element_type();
×
146
            return subset_str + subset(function, element_type, element_subset);
×
147
        } else {
×
148
            return subset_str;
1✔
149
        }
150
    } else if (auto pointer_type = dynamic_cast<const types::Pointer*>(&type)) {
3✔
151
        std::string subset_str = "[" + this->expression(sub.at(0)) + "]";
1✔
152

153
        data_flow::Subset element_subset(sub.begin() + 1, sub.end());
1✔
154
        auto& pointee_type = pointer_type->pointee_type();
1✔
155
        return subset_str + subset(function, pointee_type, element_subset);
1✔
156
    } else if (auto structure_type = dynamic_cast<const types::Structure*>(&type)) {
2✔
157
        auto& definition = function.structure(structure_type->name());
1✔
158

159
        std::string subset_str = ".member_" + this->expression(sub.at(0));
1✔
160
        if (sub.size() > 1) {
1✔
161
            auto member = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(sub.at(0));
×
162
            auto& member_type = definition.member_type(member);
×
163
            data_flow::Subset element_subset(sub.begin() + 1, sub.end());
×
164
            return subset_str + subset(function, member_type, element_subset);
×
165
        } else {
×
166
            return subset_str;
1✔
167
        }
168
    }
1✔
169

170
    throw std::invalid_argument("Invalid subset type");
×
171
};
15✔
172

173
std::string CLanguageExtension::expression(const symbolic::Expression expr) {
2,054✔
174
    CSymbolicPrinter printer(this->external_variables_);
2,054✔
175
    return printer.apply(expr);
2,054✔
176
};
2,054✔
177

178
std::string CLanguageExtension::access_node(const data_flow::AccessNode& node) {
21✔
179
    if (dynamic_cast<const data_flow::ConstantNode*>(&node)) {
21✔
180
        std::string name = node.data();
3✔
181
        if (symbolic::is_nullptr(symbolic::symbol(name))) {
3✔
182
            return this->expression(symbolic::__nullptr__());
2✔
183
        }
184
        return name;
1✔
185
    } else {
3✔
186
        std::string name = node.data();
18✔
187
        if (this->external_variables_.find(name) != this->external_variables_.end()) {
18✔
188
            return "(&" + name + ")";
×
189
        }
190
        return name;
18✔
191
    }
18✔
192
};
21✔
193

194
std::string CLanguageExtension::tasklet(const data_flow::Tasklet& tasklet) {
3✔
195
    switch (tasklet.code()) {
3✔
196
        case data_flow::TaskletCode::assign:
197
            return tasklet.inputs().at(0);
2✔
198
        case data_flow::TaskletCode::fp_neg:
NEW
199
            return "-" + tasklet.inputs().at(0);
×
200
        case data_flow::TaskletCode::fp_add:
NEW
201
            return tasklet.inputs().at(0) + " + " + tasklet.inputs().at(1);
×
202
        case data_flow::TaskletCode::fp_sub:
NEW
203
            return tasklet.inputs().at(0) + " - " + tasklet.inputs().at(1);
×
204
        case data_flow::TaskletCode::fp_mul:
NEW
205
            return tasklet.inputs().at(0) + " * " + tasklet.inputs().at(1);
×
206
        case data_flow::TaskletCode::fp_div:
NEW
207
            return tasklet.inputs().at(0) + " / " + tasklet.inputs().at(1);
×
208
        case data_flow::TaskletCode::fp_rem:
NEW
209
            return "remainder(" + tasklet.inputs().at(0) + ", " + tasklet.inputs().at(1) + ")";
×
210
        case data_flow::TaskletCode::fp_fma:
NEW
211
            return tasklet.inputs().at(0) + " * " + tasklet.inputs().at(1) + " + " + tasklet.inputs().at(2);
×
212
        case data_flow::TaskletCode::fp_oeq:
NEW
213
            return tasklet.inputs().at(0) + " == " + tasklet.inputs().at(1);
×
214
        case data_flow::TaskletCode::fp_one:
NEW
215
            return tasklet.inputs().at(0) + " != " + tasklet.inputs().at(1);
×
216
        case data_flow::TaskletCode::fp_ogt:
NEW
217
            return tasklet.inputs().at(0) + " > " + tasklet.inputs().at(1);
×
218
        case data_flow::TaskletCode::fp_oge:
NEW
219
            return tasklet.inputs().at(0) + " >= " + tasklet.inputs().at(1);
×
220
        case data_flow::TaskletCode::fp_olt:
NEW
221
            return tasklet.inputs().at(0) + " < " + tasklet.inputs().at(1);
×
222
        case data_flow::TaskletCode::fp_ole:
NEW
223
            return tasklet.inputs().at(0) + " <= " + tasklet.inputs().at(1);
×
224
        case data_flow::TaskletCode::fp_ord:
NEW
225
            return "isnan(" + tasklet.inputs().at(0) + ") && isnan(" + tasklet.inputs().at(1) + ")";
×
226
        case data_flow::TaskletCode::fp_ueq:
NEW
227
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
228
                   tasklet.inputs().at(0) + " == " + tasklet.inputs().at(1);
×
229
        case data_flow::TaskletCode::fp_une:
NEW
230
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
231
                   tasklet.inputs().at(0) + " != " + tasklet.inputs().at(1);
×
232
        case data_flow::TaskletCode::fp_ugt:
NEW
233
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
234
                   tasklet.inputs().at(0) + " > " + tasklet.inputs().at(1);
×
235
        case data_flow::TaskletCode::fp_uge:
NEW
236
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
237
                   tasklet.inputs().at(0) + " >= " + tasklet.inputs().at(1);
×
238
        case data_flow::TaskletCode::fp_ult:
NEW
239
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
240
                   tasklet.inputs().at(0) + " < " + tasklet.inputs().at(1);
×
241
        case data_flow::TaskletCode::fp_ule:
NEW
242
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")" + " || " +
×
NEW
243
                   tasklet.inputs().at(0) + " <= " + tasklet.inputs().at(1);
×
244
        case data_flow::TaskletCode::fp_uno:
NEW
245
            return "isnan(" + tasklet.inputs().at(0) + ") || isnan(" + tasklet.inputs().at(1) + ")";
×
246
        case data_flow::TaskletCode::int_add:
247
            return tasklet.inputs().at(0) + " + " + tasklet.inputs().at(1);
1✔
248
        case data_flow::TaskletCode::int_sub:
NEW
249
            return tasklet.inputs().at(0) + " - " + tasklet.inputs().at(1);
×
250
        case data_flow::TaskletCode::int_mul:
NEW
251
            return tasklet.inputs().at(0) + " * " + tasklet.inputs().at(1);
×
252
        case data_flow::TaskletCode::int_sdiv:
NEW
253
            return tasklet.inputs().at(0) + " / " + tasklet.inputs().at(1);
×
254
        case data_flow::TaskletCode::int_srem:
NEW
255
            return tasklet.inputs().at(0) + " % " + tasklet.inputs().at(1);
×
256
        case data_flow::TaskletCode::int_udiv:
NEW
257
            return tasklet.inputs().at(0) + " / " + tasklet.inputs().at(1);
×
258
        case data_flow::TaskletCode::int_urem:
NEW
259
            return tasklet.inputs().at(0) + " % " + tasklet.inputs().at(1);
×
260
        case data_flow::TaskletCode::int_and:
NEW
261
            return tasklet.inputs().at(0) + " & " + tasklet.inputs().at(1);
×
262
        case data_flow::TaskletCode::int_or:
NEW
263
            return tasklet.inputs().at(0) + " | " + tasklet.inputs().at(1);
×
264
        case data_flow::TaskletCode::int_xor:
NEW
265
            return tasklet.inputs().at(0) + " ^ " + tasklet.inputs().at(1);
×
266
        case data_flow::TaskletCode::int_shl:
NEW
267
            return tasklet.inputs().at(0) + " << " + tasklet.inputs().at(1);
×
268
        case data_flow::TaskletCode::int_lshr:
NEW
269
            return tasklet.inputs().at(0) + " >> " + tasklet.inputs().at(1);
×
270
        case data_flow::TaskletCode::int_ashr:
NEW
271
            return tasklet.inputs().at(0) + " >> " + tasklet.inputs().at(1);
×
272
        case data_flow::TaskletCode::int_eq:
NEW
273
            return tasklet.inputs().at(0) + " == " + tasklet.inputs().at(1);
×
274
        case data_flow::TaskletCode::int_ne:
NEW
275
            return tasklet.inputs().at(0) + " != " + tasklet.inputs().at(1);
×
276
        case data_flow::TaskletCode::int_sgt:
NEW
277
            return tasklet.inputs().at(0) + " > " + tasklet.inputs().at(1);
×
278
        case data_flow::TaskletCode::int_sge:
NEW
279
            return tasklet.inputs().at(0) + " >= " + tasklet.inputs().at(1);
×
280
        case data_flow::TaskletCode::int_slt:
NEW
281
            return tasklet.inputs().at(0) + " < " + tasklet.inputs().at(1);
×
282
        case data_flow::TaskletCode::int_sle:
NEW
283
            return tasklet.inputs().at(0) + " <= " + tasklet.inputs().at(1);
×
284
        case data_flow::TaskletCode::int_ugt:
NEW
285
            return tasklet.inputs().at(0) + " > " + tasklet.inputs().at(1);
×
286
        case data_flow::TaskletCode::int_uge:
NEW
287
            return tasklet.inputs().at(0) + " >= " + tasklet.inputs().at(1);
×
288
        case data_flow::TaskletCode::int_ult:
NEW
289
            return tasklet.inputs().at(0) + " < " + tasklet.inputs().at(1);
×
290
        case data_flow::TaskletCode::int_ule:
NEW
291
            return tasklet.inputs().at(0) + " <= " + tasklet.inputs().at(1);
×
292
    };
NEW
293
    throw std::invalid_argument("Invalid tasklet code");
×
294
};
3✔
295

296
std::string CLanguageExtension::zero(const types::PrimitiveType prim_type) {
×
297
    switch (prim_type) {
×
298
        case types::Void:
299
            throw InvalidSDFGException("No zero for void type possible");
×
300
        case types::Bool:
301
            return "false";
×
302
        case types::Int8:
303
            return "0";
×
304
        case types::Int16:
305
            return "0";
×
306
        case types::Int32:
307
            return "0";
×
308
        case types::Int64:
309
            return "0ll";
×
310
        case types::Int128:
311
            return "0";
×
312
        case types::UInt8:
313
            return "0u";
×
314
        case types::UInt16:
315
            return "0u";
×
316
        case types::UInt32:
317
            return "0u";
×
318
        case types::UInt64:
319
            return "0ull";
×
320
        case types::UInt128:
321
            return "0u";
×
322
        case types::Half:
323
            throw InvalidSDFGException("Currently unsupported");
×
324
        case types::BFloat:
325
            throw InvalidSDFGException("Currently unsupported");
×
326
        case types::Float:
327
            return "0.0f";
×
328
        case types::Double:
329
            return "0.0";
×
330
        case types::X86_FP80:
331
            return "0.0l";
×
332
        case types::FP128:
333
            throw InvalidSDFGException("Currently unsupported");
×
334
        case types::PPC_FP128:
335
            throw InvalidSDFGException("Currently unsupported");
×
336
    }
×
337
}
×
338

339
void CSymbolicPrinter::bvisit(const SymEngine::Infty& x) {
×
340
    if (x.is_negative_infinity())
×
341
        str_ = "-INFINITY";
×
342
    else if (x.is_positive_infinity())
×
343
        str_ = "INFINITY";
×
344
};
×
345

346
void CSymbolicPrinter::bvisit(const SymEngine::BooleanAtom& x) { str_ = x.get_val() ? "true" : "false"; };
2✔
347

348
void CSymbolicPrinter::bvisit(const SymEngine::Symbol& x) {
1,571✔
349
    if (symbolic::is_nullptr(symbolic::symbol(x.get_name()))) {
1,571✔
350
        str_ = "NULL";
2✔
351
        return;
2✔
352
    }
353
    std::string name = x.get_name();
1,569✔
354
    if (this->external_variables_.find(name) != this->external_variables_.end()) {
1,569✔
355
        name = "(&" + name + ")";
1✔
356
    }
1✔
357
    str_ = name;
1,569✔
358
};
1,571✔
359

360
void CSymbolicPrinter::bvisit(const SymEngine::And& x) {
×
361
    std::ostringstream s;
×
362
    auto container = x.get_container();
×
363
    s << apply(*container.begin());
×
364
    for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
365
        s << " && " << apply(*it);
×
366
    }
×
367
    str_ = parenthesize(s.str());
×
368
};
×
369

370
void CSymbolicPrinter::bvisit(const SymEngine::Or& x) {
×
371
    std::ostringstream s;
×
372
    auto container = x.get_container();
×
373
    s << apply(*container.begin());
×
374
    for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
375
        s << " || " << apply(*it);
×
376
    }
×
377
    str_ = parenthesize(s.str());
×
378
};
×
379

380
void CSymbolicPrinter::bvisit(const SymEngine::Not& x) {
×
381
    str_ = "!" + apply(x.get_arg());
×
382
    str_ = parenthesize(str_);
×
383
};
×
384

385
void CSymbolicPrinter::bvisit(const SymEngine::Equality& x) {
1✔
386
    str_ = apply(x.get_args()[0]) + " == " + apply(x.get_args()[1]);
1✔
387
    str_ = parenthesize(str_);
1✔
388
};
1✔
389

390
void CSymbolicPrinter::bvisit(const SymEngine::Unequality& x) {
1✔
391
    str_ = apply(x.get_args()[0]) + " != " + apply(x.get_args()[1]);
1✔
392
    str_ = parenthesize(str_);
1✔
393
};
1✔
394

395
void CSymbolicPrinter::bvisit(const SymEngine::Min& x) {
×
396
    std::ostringstream s;
×
397
    auto container = x.get_args();
×
398
    if (container.size() == 1) {
×
399
        s << apply(*container.begin());
×
400
    } else {
×
401
        s << "__daisy_min(";
×
402
        s << apply(*container.begin());
×
403

404
        // Recursively apply __daisy_min to the arguments
405
        SymEngine::vec_basic subargs;
×
406
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
407
            subargs.push_back(*it);
×
408
        }
×
409
        auto submin = SymEngine::min(subargs);
×
410
        s << ", " << apply(submin);
×
411

412
        s << ")";
×
413
    }
×
414

415
    str_ = s.str();
×
416
};
×
417

418
void CSymbolicPrinter::bvisit(const SymEngine::Max& x) {
×
419
    std::ostringstream s;
×
420
    auto container = x.get_args();
×
421
    if (container.size() == 1) {
×
422
        s << apply(*container.begin());
×
423
    } else {
×
424
        s << "__daisy_max(";
×
425
        s << apply(*container.begin());
×
426

427
        // Recursively apply __daisy_max to the arguments
428
        SymEngine::vec_basic subargs;
×
429
        for (auto it = ++(container.begin()); it != container.end(); ++it) {
×
430
            subargs.push_back(*it);
×
431
        }
×
432
        auto submax = SymEngine::max(subargs);
×
433
        s << ", " << apply(submax);
×
434

435
        s << ")";
×
436
    }
×
437

438
    str_ = s.str();
×
439
};
×
440

441
void CSymbolicPrinter::bvisit(const SymEngine::FunctionSymbol& x) {
1✔
442
    if (x.get_name() == "idiv") {
1✔
443
        str_ = "((" + apply(x.get_args()[0]) + ") / (" + apply(x.get_args()[1]) + "))";
×
444
    } else if (x.get_name() == "imod") {
1✔
445
        str_ = "((" + apply(x.get_args()[0]) + ") % (" + apply(x.get_args()[1]) + "))";
×
446
    } else if (x.get_name() == "sizeof") {
1✔
447
        auto& so = dynamic_cast<const symbolic::SizeOfTypeFunction&>(x);
1✔
448
        auto& type = so.get_type();
1✔
449
        CLanguageExtension lang;
1✔
450
        str_ = "sizeof(" + lang.declaration("", type) + ")";
1✔
451
    } else {
1✔
452
        throw std::runtime_error("Unsupported function symbol: " + x.get_name());
×
453
    }
454
};
1✔
455

456
void CSymbolicPrinter::_print_pow(
2✔
457
    std::ostringstream& o,
458
    const SymEngine::RCP<const SymEngine::Basic>& a,
459
    const SymEngine::RCP<const SymEngine::Basic>& b
460
) {
461
    if (SymEngine::eq(*a, *SymEngine::E)) {
2✔
462
        o << "exp(" << apply(b) << ")";
×
463
    } else if (SymEngine::eq(*b, *SymEngine::rational(1, 2))) {
2✔
464
        o << "sqrt(" << apply(a) << ")";
×
465
    } else if (SymEngine::eq(*b, *SymEngine::rational(1, 3))) {
2✔
466
        o << "cbrt(" << apply(a) << ")";
×
467
    } else if (SymEngine::eq(*b, *SymEngine::integer(2))) {
2✔
468
        o << "((" + apply(a) + ") * (" + apply(a) + "))";
2✔
469
    } else {
2✔
470
        o << "pow(" << apply(a) << ", " << apply(b) << ")";
×
471
    }
472
};
2✔
473

474
} // namespace codegen
475
} // 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