• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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