1 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2 // -*- mode: C++ -*-
3 //
4 // Copyright 2023-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: Aleksei Vetrov
19
20 #include "type_normalisation.h"
21
22 #include <map>
23 #include <string>
24 #include <unordered_map>
25 #include <unordered_set>
26 #include <vector>
27
28 #include "graph.h"
29
30 namespace stg {
31
32 namespace {
33
34 struct ResolveQualifiedChain {
ResolveQualifiedChainstg::__anon694f6cb90111::ResolveQualifiedChain35 ResolveQualifiedChain(const Graph& graph,
36 std::unordered_map<Id, Id>& resolved)
37 : graph(graph), resolved(resolved) {}
38
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain39 Id operator()(Id node_id) {
40 return graph.Apply(*this, node_id, node_id);
41 }
42
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain43 Id operator()(const Qualified& x, Id node_id) {
44 auto [it, emplaced] = resolved.emplace(node_id, Id::kInvalid);
45 if (!emplaced) {
46 Check(it->second != Id::kInvalid) << "qualified cycle detected";
47 return it->second;
48 }
49 return it->second = (*this)(x.qualified_type_id);
50 }
51
52 template <typename Node>
operator ()stg::__anon694f6cb90111::ResolveQualifiedChain53 Id operator()(const Node&, Id node_id) {
54 return node_id;
55 }
56
57 const Graph& graph;
58 std::unordered_map<Id, Id>& resolved;
59 };
60
61 // Traverse rooted graph and produce mapping from qualified type to
62 // non-qualified. Produced keys should not intersect with values.
63 // It also collects all functions seen during traversal.
64 struct FindQualifiedTypesAndFunctions {
FindQualifiedTypesAndFunctionsstg::__anon694f6cb90111::FindQualifiedTypesAndFunctions65 FindQualifiedTypesAndFunctions(const Graph& graph,
66 std::unordered_map<Id, Id>& resolved,
67 std::unordered_set<Id>& functions)
68 : graph(graph),
69 resolved(resolved),
70 functions(functions),
71 resolve_qualified_chain(graph, resolved) {}
72
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions73 void operator()(Id id) {
74 if (seen.insert(id).second) {
75 graph.Apply(*this, id, id);
76 }
77 }
78
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions79 void operator()(const std::vector<Id>& ids) {
80 for (const auto& id : ids) {
81 (*this)(id);
82 }
83 }
84
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions85 void operator()(const std::map<std::string, Id>& x) {
86 for (const auto& [_, id] : x) {
87 (*this)(id);
88 }
89 }
90
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions91 void operator()(const Special&, Id) {}
92
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions93 void operator()(const PointerReference& x, Id) {
94 (*this)(x.pointee_type_id);
95 }
96
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions97 void operator()(const PointerToMember& x, Id) {
98 (*this)(x.containing_type_id);
99 (*this)(x.pointee_type_id);
100 }
101
102 // Typedefs are not considered when looking for useless qualifiers.
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions103 void operator()(const Typedef& x, Id) {
104 (*this)(x.referred_type_id);
105 }
106
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions107 void operator()(const Qualified&, Id node_id) {
108 (*this)(resolve_qualified_chain(node_id));
109 }
110
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions111 void operator()(const Primitive&, Id) {}
112
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions113 void operator()(const Array& x, Id) {
114 (*this)(x.element_type_id);
115 }
116
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions117 void operator()(const BaseClass& x, Id) {
118 (*this)(x.type_id);
119 }
120
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions121 void operator()(const Method& x, Id) {
122 (*this)(x.type_id);
123 }
124
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions125 void operator()(const Member& x, Id) {
126 (*this)(x.type_id);
127 }
128
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions129 void operator()(const VariantMember& x, Id) {
130 (*this)(x.type_id);
131 }
132
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions133 void operator()(const StructUnion& x, Id) {
134 if (x.definition.has_value()) {
135 auto& definition = x.definition.value();
136 (*this)(definition.base_classes);
137 (*this)(definition.methods);
138 (*this)(definition.members);
139 }
140 }
141
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions142 void operator()(const Enumeration& x, Id) {
143 if (x.definition.has_value()) {
144 (*this)(x.definition->underlying_type_id);
145 }
146 }
147
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions148 void operator()(const Variant& x, Id) {
149 if (x.discriminant.has_value()) {
150 (*this)(x.discriminant.value());
151 }
152 (*this)(x.members);
153 }
154
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions155 void operator()(const Function& x, Id node_id) {
156 functions.emplace(node_id);
157 for (auto& id : x.parameters) {
158 (*this)(id);
159 }
160 (*this)(x.return_type_id);
161 }
162
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions163 void operator()(const ElfSymbol& x, Id) {
164 if (x.type_id) {
165 (*this)(*x.type_id);
166 }
167 }
168
operator ()stg::__anon694f6cb90111::FindQualifiedTypesAndFunctions169 void operator()(const Interface& x, Id) {
170 (*this)(x.symbols);
171 (*this)(x.types);
172 }
173
174 const Graph& graph;
175 std::unordered_map<Id, Id>& resolved;
176 std::unordered_set<Id>& functions;
177 std::unordered_set<Id> seen;
178 ResolveQualifiedChain resolve_qualified_chain;
179 };
180
181 // Remove qualifiers from function parameters and return type.
182 // "resolved" mapping should have resolutions from qualified type to
183 // non-qualified. Thus, keys and values should not intersect.
184 struct RemoveFunctionQualifiers {
RemoveFunctionQualifiersstg::__anon694f6cb90111::RemoveFunctionQualifiers185 RemoveFunctionQualifiers(Graph& graph,
186 const std::unordered_map<Id, Id>& resolved)
187 : graph(graph), resolved(resolved) {}
188
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers189 void operator()(Id id) {
190 graph.Apply(*this, id);
191 }
192
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers193 void operator()(Function& x) {
194 for (auto& id : x.parameters) {
195 RemoveQualifiers(id);
196 }
197 RemoveQualifiers(x.return_type_id);
198 }
199
200 template<typename Node>
operator ()stg::__anon694f6cb90111::RemoveFunctionQualifiers201 void operator()(Node&) {
202 Die() << "only functions should have qualifiers substituted";
203 }
204
RemoveQualifiersstg::__anon694f6cb90111::RemoveFunctionQualifiers205 void RemoveQualifiers(Id& id) {
206 const auto it = resolved.find(id);
207 if (it != resolved.end()) {
208 id = it->second;
209 Check(!resolved.contains(id)) << "qualifier was resolved to qualifier";
210 }
211 }
212
213 Graph& graph;
214 const std::unordered_map<Id, Id>& resolved;
215 };
216
217 } // namespace
218
RemoveUselessQualifiers(Graph & graph,Id root)219 Id RemoveUselessQualifiers(Graph& graph, Id root) {
220 std::unordered_map<Id, Id> resolved;
221 std::unordered_set<Id> functions;
222 FindQualifiedTypesAndFunctions(graph, resolved, functions)(root);
223
224 RemoveFunctionQualifiers remove_qualifiers(graph, resolved);
225 for (const auto& id : functions) {
226 remove_qualifiers(id);
227 }
228 return root;
229 }
230
231 } // namespace stg
232