• 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::__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