xref: /aosp_15_r20/external/stg/fidelity.cc (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
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: Siddharth Nayyar
19 
20 #include "fidelity.h"
21 
22 #include <map>
23 #include <ostream>
24 #include <set>
25 #include <string>
26 #include <unordered_map>
27 #include <utility>
28 #include <vector>
29 
30 #include "graph.h"
31 #include "naming.h"
32 
33 namespace stg {
34 
35 namespace {
36 
37 struct Fidelity {
Fidelitystg::__anon65cde4720111::Fidelity38   Fidelity(const Graph& graph, NameCache& name_cache)
39       : graph(graph), describe(graph, name_cache), seen(Id(0)) {
40     seen.Reserve(graph.Limit());
41   }
42 
43   void operator()(Id);
44   void operator()(const std::vector<Id>&);
45   void operator()(const std::map<std::string, Id>&);
46   void operator()(const Special&, Id);
47   void operator()(const PointerReference&, Id);
48   void operator()(const PointerToMember&, Id);
49   void operator()(const Typedef&, Id);
50   void operator()(const Qualified&, Id);
51   void operator()(const Primitive&, Id);
52   void operator()(const Array&, Id);
53   void operator()(const BaseClass&, Id);
54   void operator()(const Method&, Id);
55   void operator()(const Member&, Id);
56   void operator()(const VariantMember&, Id);
57   void operator()(const StructUnion&, Id);
58   void operator()(const Enumeration&, Id);
59   void operator()(const Variant&, Id);
60   void operator()(const Function&, Id);
61   void operator()(const ElfSymbol&, Id);
62   void operator()(const Interface&, Id);
63 
64   const Graph& graph;
65   Describe describe;
66   DenseIdSet seen;
67   std::unordered_map<std::string, SymbolFidelity> symbols;
68   std::unordered_map<std::string, TypeFidelity> types;
69 };
70 
operator ()(Id id)71 void Fidelity::operator()(Id id) {
72   if (seen.Insert(id)) {
73     graph.Apply(*this, id, id);
74   }
75 }
76 
operator ()(const std::vector<Id> & x)77 void Fidelity::operator()(const std::vector<Id>& x) {
78   for (auto id : x) {
79     (*this)(id);
80   }
81 }
82 
operator ()(const std::map<std::string,Id> & x)83 void Fidelity::operator()(const std::map<std::string, Id>& x) {
84   for (const auto& [_, id] : x) {
85     (*this)(id);
86   }
87 }
88 
operator ()(const Special &,Id)89 void Fidelity::operator()(const Special&, Id) {}
90 
operator ()(const PointerReference & x,Id)91 void Fidelity::operator()(const PointerReference& x, Id) {
92   (*this)(x.pointee_type_id);
93 }
94 
operator ()(const PointerToMember & x,Id)95 void Fidelity::operator()(const PointerToMember& x, Id) {
96   (*this)(x.containing_type_id);
97   (*this)(x.pointee_type_id);
98 }
99 
operator ()(const Typedef & x,Id)100 void Fidelity::operator()(const Typedef& x, Id) {
101   (*this)(x.referred_type_id);
102 }
103 
operator ()(const Qualified & x,Id)104 void Fidelity::operator()(const Qualified& x, Id) {
105   (*this)(x.qualified_type_id);
106 }
107 
operator ()(const Primitive &,Id)108 void Fidelity::operator()(const Primitive&, Id) {}
109 
operator ()(const Array & x,Id)110 void Fidelity::operator()(const Array& x, Id) {
111   (*this)(x.element_type_id);
112 }
113 
operator ()(const BaseClass & x,Id)114 void Fidelity::operator()(const BaseClass& x, Id) {
115   (*this)(x.type_id);
116 }
117 
operator ()(const Method & x,Id)118 void Fidelity::operator()(const Method& x, Id) {
119   (*this)(x.type_id);
120 }
121 
operator ()(const Member & x,Id)122 void Fidelity::operator()(const Member& x, Id) {
123   (*this)(x.type_id);
124 }
125 
operator ()(const VariantMember & x,Id)126 void Fidelity::operator()(const VariantMember& x, Id) {
127   (*this)(x.type_id);
128 }
129 
operator ()(const StructUnion & x,Id id)130 void Fidelity::operator()(const StructUnion& x, Id id) {
131   if (!x.name.empty()) {
132     auto [it, _] =
133         types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
134     if (x.definition) {
135       it->second = TypeFidelity::FULLY_DEFINED;
136     }
137   }
138   if (x.definition) {
139     (*this)(x.definition->base_classes);
140     (*this)(x.definition->methods);
141     (*this)(x.definition->members);
142   }
143 }
144 
operator ()(const Enumeration & x,Id id)145 void Fidelity::operator()(const Enumeration& x, Id id) {
146   if (!x.name.empty()) {
147     auto [it, _] =
148         types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
149     if (x.definition) {
150       it->second = TypeFidelity::FULLY_DEFINED;
151     }
152   }
153 }
154 
operator ()(const Variant & x,Id id)155 void Fidelity::operator()(const Variant& x, Id id) {
156   types.emplace(describe(id).ToString(), TypeFidelity::FULLY_DEFINED);
157   (*this)(x.members);
158 }
159 
operator ()(const Function & x,Id)160 void Fidelity::operator()(const Function& x, Id) {
161   (*this)(x.return_type_id);
162   (*this)(x.parameters);
163 }
164 
operator ()(const ElfSymbol & x,Id)165 void Fidelity::operator()(const ElfSymbol& x, Id) {
166   auto symbol = VersionedSymbolName(x);
167   auto [it, _] = symbols.emplace(symbol, SymbolFidelity::UNTYPED);
168   if (x.type_id) {
169     it->second = SymbolFidelity::TYPED;
170     (*this)(*x.type_id);
171   }
172 }
173 
operator ()(const Interface & x,Id)174 void Fidelity::operator()(const Interface& x, Id) {
175   (*this)(x.symbols);
176   (*this)(x.types);
177 }
178 
179 template <typename T>
GetKeys(const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)180 std::set<std::string> GetKeys(
181     const std::unordered_map<std::string, T>& x1,
182     const std::unordered_map<std::string, T>& x2) {
183   std::set<std::string> keys;
184   for (const auto& [key, _] : x1) {
185     keys.insert(key);
186   }
187   for (const auto& [key, _] : x2) {
188     keys.insert(key);
189   }
190   return keys;
191 }
192 
InsertTransition(FidelityDiff & diff,SymbolFidelityTransition transition,const std::string & symbol)193 void InsertTransition(FidelityDiff& diff, SymbolFidelityTransition transition,
194                       const std::string& symbol) {
195   diff.symbol_transitions[transition].push_back(symbol);
196 }
197 
InsertTransition(FidelityDiff & diff,TypeFidelityTransition transition,const std::string & type)198 void InsertTransition(FidelityDiff& diff, TypeFidelityTransition transition,
199                       const std::string& type) {
200   diff.type_transitions[transition].push_back(type);
201 }
202 
203 template <typename T>
InsertTransitions(FidelityDiff & diff,const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)204 void InsertTransitions(FidelityDiff& diff,
205                        const std::unordered_map<std::string, T>& x1,
206                        const std::unordered_map<std::string, T>& x2) {
207   for (const auto& key : GetKeys(x1, x2)) {
208     auto it1 = x1.find(key);
209     auto it2 = x2.find(key);
210     auto transition = std::make_pair(it1 == x1.end() ? T() : it1->second,
211                                      it2 == x2.end() ? T() : it2->second);
212     InsertTransition(diff, transition, key);
213   }
214 }
215 
216 }  // namespace
217 
operator <<(std::ostream & os,SymbolFidelity x)218 std::ostream& operator<<(std::ostream& os, SymbolFidelity x) {
219   switch (x) {
220     case SymbolFidelity::ABSENT:
221       return os << "ABSENT";
222     case SymbolFidelity::TYPED:
223       return os << "TYPED";
224     case SymbolFidelity::UNTYPED:
225       return os << "UNTYPED";
226   }
227 }
228 
operator <<(std::ostream & os,TypeFidelity x)229 std::ostream& operator<<(std::ostream& os, TypeFidelity x) {
230   switch (x) {
231     case TypeFidelity::ABSENT:
232       return os << "ABSENT";
233     case TypeFidelity::DECLARATION_ONLY:
234       return os << "DECLARATION_ONLY";
235     case TypeFidelity::FULLY_DEFINED:
236       return os << "FULLY_DEFINED";
237   }
238 }
239 
operator <<(std::ostream & os,SymbolFidelityTransition x)240 std::ostream& operator<<(std::ostream& os, SymbolFidelityTransition x) {
241   return os << "symbol(s) changed from " << x.first << " to " << x.second;
242 }
243 
operator <<(std::ostream & os,TypeFidelityTransition x)244 std::ostream& operator<<(std::ostream& os, TypeFidelityTransition x) {
245   return os << "type(s) changed from " << x.first << " to " << x.second;
246 }
247 
GetFidelityTransitions(const Graph & graph,Id root1,Id root2)248 FidelityDiff GetFidelityTransitions(const Graph& graph, Id root1, Id root2) {
249   NameCache name_cache;
250   Fidelity fidelity1(graph, name_cache);
251   Fidelity fidelity2(graph, name_cache);
252   fidelity1(root1);
253   fidelity2(root2);
254 
255   FidelityDiff diff;
256   InsertTransitions(diff, fidelity1.symbols, fidelity2.symbols);
257   InsertTransitions(diff, fidelity1.types, fidelity2.types);
258   return diff;
259 }
260 
261 }  // namespace stg
262