1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2022-2024 Google LLC
5 //
6 // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7 // "License"); you may not use this file except in compliance with the
8 // License. You may obtain a copy of the License at
9 //
10 // https://llvm.org/LICENSE.txt
11 //
12 // Unless required by applicable law or agreed to in writing, software
13 // distributed under the License is distributed on an "AS IS" BASIS,
14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 // See the License for the specific language governing permissions and
16 // limitations under the License.
17 //
18 // Author: Giuliano Procida
19
20 #include "type_resolution.h"
21
22 #include <cstddef>
23 #include <map>
24 #include <string>
25 #include <utility>
26 #include <vector>
27
28 #include "graph.h"
29 #include "runtime.h"
30 #include "unification.h"
31
32 namespace stg {
33
34 namespace {
35
36 // Collect named type definition and declaration nodes.
37 struct NamedTypes {
NamedTypesstg::__anon7733508b0111::NamedTypes38 NamedTypes(Runtime& runtime, const Graph& graph)
39 : graph(graph),
40 seen(Id(0)),
41 nodes(runtime, "named_types.nodes"),
42 types(runtime, "named_types.types"),
43 definitions(runtime, "named_types.definitions"),
44 declarations(runtime, "named_types.declarations") {
45 seen.Reserve(graph.Limit());
46 }
47
48 enum class Tag { STRUCT, UNION, ENUM, TYPEDEF, VARIANT };
49 using Type = std::pair<Tag, std::string>;
50 struct Info {
51 std::vector<Id> definitions;
52 std::vector<Id> declarations;
53 };
54
operator ()stg::__anon7733508b0111::NamedTypes55 void operator()(const std::vector<Id>& ids) {
56 for (auto id : ids) {
57 (*this)(id);
58 }
59 }
60
operator ()stg::__anon7733508b0111::NamedTypes61 void operator()(const std::map<std::string, Id>& x) {
62 for (const auto& [_, id] : x) {
63 (*this)(id);
64 }
65 }
66
67 // main entry point
operator ()stg::__anon7733508b0111::NamedTypes68 void operator()(Id id) {
69 if (seen.Insert(id)) {
70 ++nodes;
71 graph.Apply<void>(*this, id, id);
72 }
73 }
74
GetInfostg::__anon7733508b0111::NamedTypes75 Info& GetInfo(Tag tag, const std::string& name) {
76 auto [it, inserted] = type_info.insert({{tag, name}, {}});
77 if (inserted) {
78 ++types;
79 }
80 return it->second;
81 }
82
83 // Graph function implementation
operator ()stg::__anon7733508b0111::NamedTypes84 void operator()(const Special&, Id) {}
85
operator ()stg::__anon7733508b0111::NamedTypes86 void operator()(const PointerReference& x, Id) {
87 (*this)(x.pointee_type_id);
88 }
89
operator ()stg::__anon7733508b0111::NamedTypes90 void operator()(const PointerToMember& x, Id) {
91 (*this)(x.containing_type_id);
92 (*this)(x.pointee_type_id);
93 }
94
operator ()stg::__anon7733508b0111::NamedTypes95 void operator()(const Typedef& x, Id id) {
96 auto& info = GetInfo(Tag::TYPEDEF, x.name);
97 info.definitions.push_back(id);
98 ++definitions;
99 (*this)(x.referred_type_id);
100 }
101
operator ()stg::__anon7733508b0111::NamedTypes102 void operator()(const Qualified& x, Id) {
103 (*this)(x.qualified_type_id);
104 }
105
operator ()stg::__anon7733508b0111::NamedTypes106 void operator()(const Primitive&, Id) {}
107
operator ()stg::__anon7733508b0111::NamedTypes108 void operator()(const Array& x, Id) {
109 (*this)(x.element_type_id);
110 }
111
operator ()stg::__anon7733508b0111::NamedTypes112 void operator()(const BaseClass& x, Id) {
113 (*this)(x.type_id);
114 }
115
operator ()stg::__anon7733508b0111::NamedTypes116 void operator()(const Method& x, Id) {
117 (*this)(x.type_id);
118 }
119
operator ()stg::__anon7733508b0111::NamedTypes120 void operator()(const Member& x, Id) {
121 (*this)(x.type_id);
122 }
123
operator ()stg::__anon7733508b0111::NamedTypes124 void operator()(const VariantMember& x, Id) {
125 (*this)(x.type_id);
126 }
127
operator ()stg::__anon7733508b0111::NamedTypes128 void operator()(const StructUnion& x, Id id) {
129 auto tag = x.kind == StructUnion::Kind::STRUCT ? Tag::STRUCT : Tag::UNION;
130 const auto& name = x.name;
131 const bool named = !name.empty();
132 auto& info = GetInfo(tag, name);
133 if (x.definition.has_value()) {
134 if (named) {
135 info.definitions.push_back(id);
136 ++definitions;
137 }
138 const auto& definition = *x.definition;
139 (*this)(definition.base_classes);
140 (*this)(definition.methods);
141 (*this)(definition.members);
142 } else if (named) {
143 info.declarations.push_back(id);
144 ++declarations;
145 }
146 }
147
operator ()stg::__anon7733508b0111::NamedTypes148 void operator()(const Enumeration& x, Id id) {
149 const auto& name = x.name;
150 const bool named = !name.empty();
151 auto& info = GetInfo(Tag::ENUM, name);
152 if (x.definition) {
153 if (named) {
154 info.definitions.push_back(id);
155 ++definitions;
156 }
157 } else if (named) {
158 info.declarations.push_back(id);
159 ++declarations;
160 }
161 }
162
operator ()stg::__anon7733508b0111::NamedTypes163 void operator()(const Variant& x, Id id) {
164 const auto& name = x.name;
165 auto& info = GetInfo(Tag::VARIANT, name);
166 info.definitions.push_back(id);
167 ++definitions;
168 (*this)(x.members);
169 }
170
operator ()stg::__anon7733508b0111::NamedTypes171 void operator()(const Function& x, Id) {
172 (*this)(x.return_type_id);
173 (*this)(x.parameters);
174 }
175
operator ()stg::__anon7733508b0111::NamedTypes176 void operator()(const ElfSymbol& x, Id) {
177 if (x.type_id.has_value()) {
178 (*this)(x.type_id.value());
179 }
180 }
181
operator ()stg::__anon7733508b0111::NamedTypes182 void operator()(const Interface& x, Id) {
183 (*this)(x.symbols);
184 (*this)(x.types);
185 }
186
187 const Graph& graph;
188 // ordered map for consistency and sequential processing of related types
189 std::map<Type, Info> type_info;
190 DenseIdSet seen;
191 Counter nodes;
192 Counter types;
193 Counter definitions;
194 Counter declarations;
195 };
196
197 } // namespace
198
ResolveTypes(Runtime & runtime,Graph & graph,Unification & unification,const std::vector<Id> & roots)199 void ResolveTypes(Runtime& runtime, Graph& graph, Unification& unification,
200 const std::vector<Id>& roots) {
201 const Time total(runtime, "resolve.total");
202
203 // collect named types
204 NamedTypes named_types(runtime, graph);
205 {
206 const Time time(runtime, "resolve.collection");
207 for (const Id& root : roots) {
208 named_types(root);
209 }
210 }
211
212 {
213 const Time time(runtime, "resolve.unification");
214 Counter definition_unified(runtime, "resolve.definition.unified");
215 Counter definition_not_unified(runtime, "resolve.definition.not_unified");
216 Counter declaration_unified(runtime, "resolve.declaration.unified");
217 for (auto& [_, info] : named_types.type_info) {
218 // try to unify the type definitions
219 auto& definitions = info.definitions;
220 std::vector<Id> distinct_definitions;
221 while (!definitions.empty()) {
222 const Id candidate = definitions[0];
223 std::vector<Id> todo;
224 distinct_definitions.push_back(candidate);
225 for (size_t i = 1; i < definitions.size(); ++i) {
226 if (unification.Unify(definitions[i], candidate)) {
227 // unification succeeded
228 ++definition_unified;
229 } else {
230 // unification failed, conflicting definitions
231 todo.push_back(definitions[i]);
232 ++definition_not_unified;
233 }
234 }
235 std::swap(todo, definitions);
236 }
237 // if no conflicts, map all declarations to the definition
238 if (distinct_definitions.size() == 1) {
239 const Id candidate = distinct_definitions[0];
240 for (auto id : info.declarations) {
241 unification.Union(id, candidate);
242 ++declaration_unified;
243 }
244 }
245 }
246 }
247 }
248
249 } // namespace stg
250