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

daisytuner / sdfglib / 16831424340

08 Aug 2025 01:18PM UTC coverage: 64.338% (-0.3%) from 64.684%
16831424340

Pull #182

github

web-flow
Merge 317f917f8 into 104fa63dd
Pull Request #182: Offload opaque pointers

0 of 74 new or added lines in 1 file covered. (0.0%)

14 existing lines in 1 file now uncovered.

8916 of 13858 relevant lines covered (64.34%)

117.36 hits per line

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

46.15
/src/types/utils.cpp
1
#include "sdfg/types/utils.h"
2
#include <iostream>
3
#include <memory>
4
#include <string>
5

6
#include "sdfg/analysis/users.h"
7
#include "sdfg/codegen/utils.h"
8
#include "sdfg/data_flow/access_node.h"
9
#include "sdfg/function.h"
10
#include "sdfg/structured_sdfg.h"
11
#include "sdfg/symbolic/symbolic.h"
12

13
#include "sdfg/codegen/language_extensions/c_language_extension.h"
14
#include "sdfg/types/type.h"
15

16
namespace sdfg {
17
namespace types {
18

19
const types::IType&
20
infer_type_internal(const sdfg::Function& function, const types::IType& type, const data_flow::Subset& subset) {
994✔
21
    if (subset.empty()) {
994✔
22
        return type;
495✔
23
    }
24

25
    if (type.type_id() == TypeID::Scalar) {
499✔
26
        if (!subset.empty()) {
×
27
            throw InvalidSDFGException("Scalar type must have no subset");
×
28
        }
29

30
        return type;
×
31
    } else if (type.type_id() == TypeID::Array) {
499✔
32
        auto& array_type = static_cast<const types::Array&>(type);
498✔
33

34
        data_flow::Subset element_subset(subset.begin() + 1, subset.end());
498✔
35
        return infer_type_internal(function, array_type.element_type(), element_subset);
498✔
36
    } else if (type.type_id() == TypeID::Structure) {
499✔
37
        auto& structure_type = static_cast<const types::Structure&>(type);
1✔
38

39
        auto& definition = function.structure(structure_type.name());
1✔
40

41
        data_flow::Subset element_subset(subset.begin() + 1, subset.end());
1✔
42
        auto member = SymEngine::rcp_dynamic_cast<const SymEngine::Integer>(subset.at(0));
1✔
43
        return infer_type_internal(function, definition.member_type(member), element_subset);
1✔
44
    } else if (type.type_id() == TypeID::Pointer) {
1✔
45
        throw InvalidSDFGException("Subset references non-contiguous memory");
×
46
    }
47

48
    throw InvalidSDFGException("Type inference failed because of unknown type");
×
49
};
994✔
50

51
const types::IType& infer_type(const sdfg::Function& function, const types::IType& type, const data_flow::Subset& subset) {
1,370✔
52
    if (subset.empty()) {
1,370✔
53
        return type;
875✔
54
    }
55

56
    if (type.type_id() == TypeID::Pointer) {
495✔
57
        auto& pointer_type = static_cast<const types::Pointer&>(type);
250✔
58
        if (!pointer_type.has_pointee_type()) {
250✔
59
            throw InvalidSDFGException("Non-empty subset for pointer type without pointee type");
×
60
        }
61

62
        auto& pointee_type = pointer_type.pointee_type();
250✔
63

64
        data_flow::Subset element_subset(subset.begin() + 1, subset.end());
250✔
65
        return infer_type_internal(function, pointee_type, element_subset);
250✔
66
    } else {
250✔
67
        return infer_type_internal(function, type, subset);
245✔
68
    }
69
};
1,370✔
70

71
std::unique_ptr<types::IType> recombine_array_type(const types::IType& type, uint depth, const types::IType& inner_type) {
21✔
72
    if (depth == 0) {
21✔
73
        return inner_type.clone();
9✔
74
    } else {
75
        if (auto atype = dynamic_cast<const types::Array*>(&type)) {
12✔
76
            return std::make_unique<types::Array>(
12✔
77
                atype->storage_type(),
12✔
78
                atype->alignment(),
12✔
79
                atype->initializer(),
12✔
80
                *recombine_array_type(atype->element_type(), depth - 1, inner_type).get(),
12✔
81
                atype->num_elements()
12✔
82
            );
83
        } else {
84
            throw std::runtime_error("construct_type: Non array types are not supported yet!");
×
85
        }
86
    }
87
};
21✔
88

89
const IType& peel_to_innermost_element(const IType& type, int follow_ptr) {
13✔
90
    int next_follow = follow_ptr;
13✔
91
    if (follow_ptr == PEEL_TO_INNERMOST_ELEMENT_FOLLOW_ONLY_OUTER_PTR) {
13✔
92
        next_follow = 0; // only follow an outermost pointer
5✔
93
    }
5✔
94

95
    switch (type.type_id()) {
13✔
96
        case TypeID::Array:
97
            return peel_to_innermost_element(dynamic_cast<const types::Array&>(type).element_type(), next_follow);
3✔
98
        case TypeID::Reference:
99
            return peel_to_innermost_element(dynamic_cast<const codegen::Reference&>(type).reference_type(), next_follow);
×
100
        case TypeID::Pointer:
101
            if (follow_ptr != 0) {
6✔
102
                if (follow_ptr != PEEL_TO_INNERMOST_ELEMENT_FOLLOW_ONLY_OUTER_PTR) {
5✔
103
                    next_follow = follow_ptr - 1; // follow one less pointer
×
104
                }
×
105

106
                auto& pointer_type = dynamic_cast<const types::Pointer&>(type);
5✔
107
                if (pointer_type.has_pointee_type()) {
5✔
108
                    return peel_to_innermost_element(pointer_type.pointee_type(), next_follow);
5✔
109
                } else {
110
                    return type;
×
111
                }
112
            }
113
            // fall back to cut-off if we did not follow the pointer
114
        default:
115
            return type;
5✔
116
    }
117
}
13✔
118

119
symbolic::Expression get_contiguous_element_size(const types::IType& type, bool allow_comp_time_eval) {
5✔
120
    // need to peel explicitly, primitive_type() would follow ALL pointers, even ***, even though this is not contiguous
121
    auto& innermost = peel_to_innermost_element(type, PEEL_TO_INNERMOST_ELEMENT_FOLLOW_ONLY_OUTER_PTR);
5✔
122

123
    return get_type_size(innermost, allow_comp_time_eval);
5✔
124
}
125

126
symbolic::Expression get_type_size(const types::IType& type, bool allow_comp_time_eval) {
13✔
127
    bool only_symbolic = false;
13✔
128

129
    auto id = type.type_id();
13✔
130
    if (id == TypeID::Pointer || id == TypeID::Reference || id == TypeID::Function) {
13✔
131
        // TODO NEED target info to know pointer size (4 or 8 bytes?) !!
132
        only_symbolic = true;
4✔
133
    } else if (id == TypeID::Structure) {
13✔
134
        // TODO if we have the target definition, we could evaluate the StructureDefinition to a size
135
        only_symbolic = true;
5✔
136
    } else if (id == TypeID::Array) {
9✔
137
        auto& arr = dynamic_cast<const types::Array&>(type);
1✔
138
        auto inner_element_size = get_type_size(arr.element_type(), allow_comp_time_eval);
1✔
139
        if (!inner_element_size.is_null()) {
1✔
140
            return symbolic::mul(inner_element_size, arr.num_elements());
1✔
141
        } else {
142
            return {};
×
143
        }
144
    }
1✔
145

146
    if (only_symbolic) {
12✔
147
        // Could not statically figure out the size
148
        // Could be struct we could evaluate by its definition or sth. we do not understand here
149
        if (allow_comp_time_eval) {
9✔
150
            return symbolic::size_of_type(type);
5✔
151
        } else { // size unknown
152
            return {};
4✔
153
        }
154
    } else { // should just be a primitive type
155
        auto prim_type = type.primitive_type();
3✔
156

157
        long size_of_type = static_cast<long>(types::bit_width(prim_type)) / 8;
3✔
158
        if (size_of_type != 0) {
3✔
159
            return symbolic::integer(size_of_type);
3✔
160
        } else {
161
            codegen::CLanguageExtension lang;
×
162
            std::cerr << "Unexpected primitive_type " << primitive_type_to_string(prim_type) << " of "
×
163
                      << lang.declaration("", type) << ", unknown size";
×
164
            return {};
×
165
        }
×
166
    }
167
}
13✔
168

NEW
169
std::unique_ptr<typename types::IType> infer_type_from_container(
×
170
    analysis::AnalysisManager& analysis_manager, const StructuredSDFG& sdfg, std::string container
171
) {
NEW
172
    if (sdfg.type(container).type_id() == types::TypeID::Scalar) {
×
NEW
173
        return sdfg.type(container).clone();
×
174
    }
175

NEW
176
    std::unique_ptr<typename types::IType> type = nullptr;
×
NEW
177
    auto& users = analysis_manager.get<analysis::Users>();
×
178

NEW
179
    for (auto user : users.reads(container)) {
×
NEW
180
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(user->element())) {
×
NEW
181
            for (auto& memlet : user->parent()->out_edges(*access_node)) {
×
NEW
182
                if (type == nullptr) {
×
NEW
183
                    if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
184
                        auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
185
                        if (pointer_type->has_pointee_type()) {
×
NEW
186
                            type = memlet.base_type().clone();
×
NEW
187
                        }
×
NEW
188
                    } else {
×
NEW
189
                        type = memlet.base_type().clone();
×
190
                    }
NEW
191
                } else {
×
NEW
192
                    if (*type != memlet.base_type()) {
×
NEW
193
                        if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
194
                            auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
195
                            if (pointer_type->has_pointee_type()) {
×
NEW
196
                                throw std::runtime_error("Container " + container + " has multiple types");
×
197
                            }
NEW
198
                        }
×
NEW
199
                    }
×
200
                }
201
            }
NEW
202
        }
×
203
    }
204

NEW
205
    for (auto user : users.writes(container)) {
×
NEW
206
        if (auto access_node = dynamic_cast<data_flow::AccessNode*>(user->element())) {
×
NEW
207
            for (auto& memlet : user->parent()->in_edges(*access_node)) {
×
NEW
208
                if (type == nullptr) {
×
NEW
209
                    if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
210
                        auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
211
                        if (pointer_type->has_pointee_type()) {
×
NEW
212
                            type = memlet.base_type().clone();
×
NEW
213
                        }
×
NEW
214
                    } else {
×
NEW
215
                        type = memlet.base_type().clone();
×
216
                    }
NEW
217
                } else {
×
NEW
218
                    if (*type != memlet.base_type()) {
×
NEW
219
                        if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
220
                            auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
221
                            if (pointer_type->has_pointee_type()) {
×
NEW
222
                                throw std::runtime_error("Container " + container + " has multiple types");
×
223
                            }
NEW
224
                        }
×
NEW
225
                    }
×
226
                }
227
            }
NEW
228
        }
×
229
    }
230

NEW
231
    if (type == nullptr) {
×
NEW
232
        for (auto user : users.views(container)) {
×
NEW
233
            if (auto access_node = dynamic_cast<data_flow::AccessNode*>(user->element())) {
×
NEW
234
                for (auto& memlet : user->parent()->out_edges(*access_node)) {
×
NEW
235
                    if (auto dest = dynamic_cast<data_flow::AccessNode*>(&memlet.dst())) {
×
NEW
236
                        auto infered_type = infer_type_from_container(analysis_manager, sdfg, dest->data());
×
NEW
237
                        if (type == nullptr) {
×
NEW
238
                            if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
239
                                auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
240
                                if (pointer_type->has_pointee_type()) {
×
NEW
241
                                    type = memlet.base_type().clone();
×
NEW
242
                                }
×
NEW
243
                            } else {
×
NEW
244
                                type = memlet.base_type().clone();
×
245
                            }
NEW
246
                        } else {
×
NEW
UNCOV
247
                            if (*type != memlet.base_type()) {
×
NEW
UNCOV
248
                                if (memlet.base_type().type_id() == types::TypeID::Pointer) {
×
NEW
UNCOV
249
                                    auto pointer_type = dynamic_cast<const types::Pointer*>(&memlet.base_type());
×
NEW
UNCOV
250
                                    if (pointer_type->has_pointee_type()) {
×
NEW
UNCOV
251
                                        throw std::runtime_error("Container " + container + " has multiple types");
×
252
                                    }
NEW
UNCOV
253
                                }
×
NEW
UNCOV
254
                            }
×
255
                        }
NEW
UNCOV
256
                    }
×
257
                }
NEW
UNCOV
258
            }
×
259
        }
NEW
UNCOV
260
    }
×
261

NEW
UNCOV
262
    if (type == nullptr) {
×
NEW
UNCOV
263
        throw std::runtime_error("Container " + container + " has no type");
×
264
    }
265

NEW
UNCOV
266
    return type;
×
NEW
UNCOV
267
}
×
268

269
} // namespace types
270
} // 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