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::__anon89002d6d0111::NamedTypes38 NamedTypes(Runtime& runtime, const Graph& graph)
39 : graph(graph),
40 seen(Id(0), graph.Limit()),
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
46 enum class Tag { STRUCT, UNION, ENUM, TYPEDEF, VARIANT };
47 using Type = std::pair<Tag, std::string>;
48 struct Info {
49 std::vector<Id> definitions;
50 std::vector<Id> declarations;
51 };
52
operator ()stg::__anon89002d6d0111::NamedTypes53 void operator()(const std::vector<Id>& ids) {
54 for (auto id : ids) {
55 (*this)(id);
56 }
57 }
58
operator ()stg::__anon89002d6d0111::NamedTypes59 void operator()(const std::map<std::string, Id>& x) {
60 for (const auto& [_, id] : x) {
61 (*this)(id);
62 }
63 }
64
65 // main entry point
operator ()stg::__anon89002d6d0111::NamedTypes66 void operator()(Id id) {
67 if (seen.Insert(id)) {
68 ++nodes;
69 graph.Apply(*this, id, id);
70 }
71 }
72
GetInfostg::__anon89002d6d0111::NamedTypes73 Info& GetInfo(Tag tag, const std::string& name) {
74 auto [it, inserted] = type_info.insert({{tag, name}, {}});
75 if (inserted) {
76 ++types;
77 }
78 return it->second;
79 }
80
81 // Graph function implementation
operator ()stg::__anon89002d6d0111::NamedTypes82 void operator()(const Special&, Id) {}
83
operator ()stg::__anon89002d6d0111::NamedTypes84 void operator()(const PointerReference& x, Id) {
85 (*this)(x.pointee_type_id);
86 }
87
operator ()stg::__anon89002d6d0111::NamedTypes88 void operator()(const PointerToMember& x, Id) {
89 (*this)(x.containing_type_id);
90 (*this)(x.pointee_type_id);
91 }
92
operator ()stg::__anon89002d6d0111::NamedTypes93 void operator()(const Typedef& x, Id id) {
94 auto& info = GetInfo(Tag::TYPEDEF, x.name);
95 info.definitions.push_back(id);
96 ++definitions;
97 (*this)(x.referred_type_id);
98 }
99
operator ()stg::__anon89002d6d0111::NamedTypes100 void operator()(const Qualified& x, Id) {
101 (*this)(x.qualified_type_id);
102 }
103
operator ()stg::__anon89002d6d0111::NamedTypes104 void operator()(const Primitive&, Id) {}
105
operator ()stg::__anon89002d6d0111::NamedTypes106 void operator()(const Array& x, Id) {
107 (*this)(x.element_type_id);
108 }
109
operator ()stg::__anon89002d6d0111::NamedTypes110 void operator()(const BaseClass& x, Id) {
111 (*this)(x.type_id);
112 }
113
operator ()stg::__anon89002d6d0111::NamedTypes114 void operator()(const Method& x, Id) {
115 (*this)(x.type_id);
116 }
117
operator ()stg::__anon89002d6d0111::NamedTypes118 void operator()(const Member& x, Id) {
119 (*this)(x.type_id);
120 }
121
operator ()stg::__anon89002d6d0111::NamedTypes122 void operator()(const VariantMember& x, Id) {
123 (*this)(x.type_id);
124 }
125
operator ()stg::__anon89002d6d0111::NamedTypes126 void operator()(const StructUnion& x, Id id) {
127 auto tag = x.kind == StructUnion::Kind::STRUCT ? Tag::STRUCT : Tag::UNION;
128 const auto& name = x.name;
129 const bool named = !name.empty();
130 auto& info = GetInfo(tag, name);
131 if (x.definition.has_value()) {
132 if (named) {
133 info.definitions.push_back(id);
134 ++definitions;
135 }
136 const auto& definition = *x.definition;
137 (*this)(definition.base_classes);
138 (*this)(definition.methods);
139 (*this)(definition.members);
140 } else if (named) {
141 info.declarations.push_back(id);
142 ++declarations;
143 }
144 }
145
operator ()stg::__anon89002d6d0111::NamedTypes146 void operator()(const Enumeration& x, Id id) {
147 const auto& name = x.name;
148 const bool named = !name.empty();
149 auto& info = GetInfo(Tag::ENUM, name);
150 if (x.definition) {
151 if (named) {
152 info.definitions.push_back(id);
153 ++definitions;
154 }
155 } else if (named) {
156 info.declarations.push_back(id);
157 ++declarations;
158 }
159 }
160
operator ()stg::__anon89002d6d0111::NamedTypes161 void operator()(const Variant& x, Id id) {
162 const auto& name = x.name;
163 auto& info = GetInfo(Tag::VARIANT, name);
164 info.definitions.push_back(id);
165 ++definitions;
166 (*this)(x.members);
167 }
168
operator ()stg::__anon89002d6d0111::NamedTypes169 void operator()(const Function& x, Id) {
170 (*this)(x.return_type_id);
171 (*this)(x.parameters);
172 }
173
operator ()stg::__anon89002d6d0111::NamedTypes174 void operator()(const ElfSymbol& x, Id) {
175 if (x.type_id.has_value()) {
176 (*this)(x.type_id.value());
177 }
178 }
179
operator ()stg::__anon89002d6d0111::NamedTypes180 void operator()(const Interface& x, Id) {
181 (*this)(x.symbols);
182 (*this)(x.types);
183 }
184
185 const Graph& graph;
186 // ordered map for consistency and sequential processing of related types
187 std::map<Type, Info> type_info;
188 DenseIdSet seen;
189 Counter nodes;
190 Counter types;
191 Counter definitions;
192 Counter declarations;
193 };
194
195 } // namespace
196
ResolveTypes(Runtime & runtime,Graph & graph,Unification & unification,const std::vector<Id> & roots)197 void ResolveTypes(Runtime& runtime, Graph& graph, Unification& unification,
198 const std::vector<Id>& roots) {
199 const Time total(runtime, "resolve.total");
200
201 // collect named types
202 NamedTypes named_types(runtime, graph);
203 {
204 const Time time(runtime, "resolve.collection");
205 for (const Id& root : roots) {
206 named_types(root);
207 }
208 }
209
210 {
211 const Time time(runtime, "resolve.unification");
212 Counter definition_unified(runtime, "resolve.definition.unified");
213 Counter definition_not_unified(runtime, "resolve.definition.not_unified");
214 Counter declaration_unified(runtime, "resolve.declaration.unified");
215 for (auto& [_, info] : named_types.type_info) {
216 // try to unify the type definitions
217 auto& definitions = info.definitions;
218 std::vector<Id> distinct_definitions;
219 while (!definitions.empty()) {
220 const Id candidate = definitions[0];
221 std::vector<Id> todo;
222 distinct_definitions.push_back(candidate);
223 for (size_t i = 1; i < definitions.size(); ++i) {
224 if (unification.Unify(definitions[i], candidate)) {
225 // unification succeeded
226 ++definition_unified;
227 } else {
228 // unification failed, conflicting definitions
229 todo.push_back(definitions[i]);
230 ++definition_not_unified;
231 }
232 }
233 std::swap(todo, definitions);
234 }
235 // if no conflicts, map all declarations to the definition
236 if (distinct_definitions.size() == 1) {
237 const Id candidate = distinct_definitions[0];
238 for (auto id : info.declarations) {
239 unification.Union(id, candidate);
240 ++declaration_unified;
241 }
242 }
243 }
244 }
245 }
246
247 } // namespace stg
248