1*9e3b08aeSAndroid Build Coastguard Worker // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
2*9e3b08aeSAndroid Build Coastguard Worker // -*- mode: C++ -*-
3*9e3b08aeSAndroid Build Coastguard Worker //
4*9e3b08aeSAndroid Build Coastguard Worker // Copyright 2023-2024 Google LLC
5*9e3b08aeSAndroid Build Coastguard Worker //
6*9e3b08aeSAndroid Build Coastguard Worker // Licensed under the Apache License v2.0 with LLVM Exceptions (the
7*9e3b08aeSAndroid Build Coastguard Worker // "License"); you may not use this file except in compliance with the
8*9e3b08aeSAndroid Build Coastguard Worker // License. You may obtain a copy of the License at
9*9e3b08aeSAndroid Build Coastguard Worker //
10*9e3b08aeSAndroid Build Coastguard Worker // https://llvm.org/LICENSE.txt
11*9e3b08aeSAndroid Build Coastguard Worker //
12*9e3b08aeSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
13*9e3b08aeSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
14*9e3b08aeSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*9e3b08aeSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
16*9e3b08aeSAndroid Build Coastguard Worker // limitations under the License.
17*9e3b08aeSAndroid Build Coastguard Worker //
18*9e3b08aeSAndroid Build Coastguard Worker // Author: Siddharth Nayyar
19*9e3b08aeSAndroid Build Coastguard Worker
20*9e3b08aeSAndroid Build Coastguard Worker #include "fidelity.h"
21*9e3b08aeSAndroid Build Coastguard Worker
22*9e3b08aeSAndroid Build Coastguard Worker #include <map>
23*9e3b08aeSAndroid Build Coastguard Worker #include <ostream>
24*9e3b08aeSAndroid Build Coastguard Worker #include <set>
25*9e3b08aeSAndroid Build Coastguard Worker #include <string>
26*9e3b08aeSAndroid Build Coastguard Worker #include <unordered_map>
27*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
28*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
29*9e3b08aeSAndroid Build Coastguard Worker
30*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
31*9e3b08aeSAndroid Build Coastguard Worker #include "naming.h"
32*9e3b08aeSAndroid Build Coastguard Worker
33*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
34*9e3b08aeSAndroid Build Coastguard Worker
35*9e3b08aeSAndroid Build Coastguard Worker namespace {
36*9e3b08aeSAndroid Build Coastguard Worker
37*9e3b08aeSAndroid Build Coastguard Worker struct Fidelity {
Fidelitystg::__anon65cde4720111::Fidelity38*9e3b08aeSAndroid Build Coastguard Worker Fidelity(const Graph& graph, NameCache& name_cache)
39*9e3b08aeSAndroid Build Coastguard Worker : graph(graph), describe(graph, name_cache), seen(Id(0)) {
40*9e3b08aeSAndroid Build Coastguard Worker seen.Reserve(graph.Limit());
41*9e3b08aeSAndroid Build Coastguard Worker }
42*9e3b08aeSAndroid Build Coastguard Worker
43*9e3b08aeSAndroid Build Coastguard Worker void operator()(Id);
44*9e3b08aeSAndroid Build Coastguard Worker void operator()(const std::vector<Id>&);
45*9e3b08aeSAndroid Build Coastguard Worker void operator()(const std::map<std::string, Id>&);
46*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Special&, Id);
47*9e3b08aeSAndroid Build Coastguard Worker void operator()(const PointerReference&, Id);
48*9e3b08aeSAndroid Build Coastguard Worker void operator()(const PointerToMember&, Id);
49*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Typedef&, Id);
50*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Qualified&, Id);
51*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Primitive&, Id);
52*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Array&, Id);
53*9e3b08aeSAndroid Build Coastguard Worker void operator()(const BaseClass&, Id);
54*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Method&, Id);
55*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Member&, Id);
56*9e3b08aeSAndroid Build Coastguard Worker void operator()(const VariantMember&, Id);
57*9e3b08aeSAndroid Build Coastguard Worker void operator()(const StructUnion&, Id);
58*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Enumeration&, Id);
59*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Variant&, Id);
60*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Function&, Id);
61*9e3b08aeSAndroid Build Coastguard Worker void operator()(const ElfSymbol&, Id);
62*9e3b08aeSAndroid Build Coastguard Worker void operator()(const Interface&, Id);
63*9e3b08aeSAndroid Build Coastguard Worker
64*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
65*9e3b08aeSAndroid Build Coastguard Worker Describe describe;
66*9e3b08aeSAndroid Build Coastguard Worker DenseIdSet seen;
67*9e3b08aeSAndroid Build Coastguard Worker std::unordered_map<std::string, SymbolFidelity> symbols;
68*9e3b08aeSAndroid Build Coastguard Worker std::unordered_map<std::string, TypeFidelity> types;
69*9e3b08aeSAndroid Build Coastguard Worker };
70*9e3b08aeSAndroid Build Coastguard Worker
operator ()(Id id)71*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(Id id) {
72*9e3b08aeSAndroid Build Coastguard Worker if (seen.Insert(id)) {
73*9e3b08aeSAndroid Build Coastguard Worker graph.Apply(*this, id, id);
74*9e3b08aeSAndroid Build Coastguard Worker }
75*9e3b08aeSAndroid Build Coastguard Worker }
76*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const std::vector<Id> & x)77*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const std::vector<Id>& x) {
78*9e3b08aeSAndroid Build Coastguard Worker for (auto id : x) {
79*9e3b08aeSAndroid Build Coastguard Worker (*this)(id);
80*9e3b08aeSAndroid Build Coastguard Worker }
81*9e3b08aeSAndroid Build Coastguard Worker }
82*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const std::map<std::string,Id> & x)83*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const std::map<std::string, Id>& x) {
84*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [_, id] : x) {
85*9e3b08aeSAndroid Build Coastguard Worker (*this)(id);
86*9e3b08aeSAndroid Build Coastguard Worker }
87*9e3b08aeSAndroid Build Coastguard Worker }
88*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Special &,Id)89*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Special&, Id) {}
90*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const PointerReference & x,Id)91*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const PointerReference& x, Id) {
92*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.pointee_type_id);
93*9e3b08aeSAndroid Build Coastguard Worker }
94*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const PointerToMember & x,Id)95*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const PointerToMember& x, Id) {
96*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.containing_type_id);
97*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.pointee_type_id);
98*9e3b08aeSAndroid Build Coastguard Worker }
99*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Typedef & x,Id)100*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Typedef& x, Id) {
101*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.referred_type_id);
102*9e3b08aeSAndroid Build Coastguard Worker }
103*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Qualified & x,Id)104*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Qualified& x, Id) {
105*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.qualified_type_id);
106*9e3b08aeSAndroid Build Coastguard Worker }
107*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Primitive &,Id)108*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Primitive&, Id) {}
109*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Array & x,Id)110*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Array& x, Id) {
111*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.element_type_id);
112*9e3b08aeSAndroid Build Coastguard Worker }
113*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const BaseClass & x,Id)114*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const BaseClass& x, Id) {
115*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.type_id);
116*9e3b08aeSAndroid Build Coastguard Worker }
117*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Method & x,Id)118*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Method& x, Id) {
119*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.type_id);
120*9e3b08aeSAndroid Build Coastguard Worker }
121*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Member & x,Id)122*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Member& x, Id) {
123*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.type_id);
124*9e3b08aeSAndroid Build Coastguard Worker }
125*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const VariantMember & x,Id)126*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const VariantMember& x, Id) {
127*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.type_id);
128*9e3b08aeSAndroid Build Coastguard Worker }
129*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const StructUnion & x,Id id)130*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const StructUnion& x, Id id) {
131*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty()) {
132*9e3b08aeSAndroid Build Coastguard Worker auto [it, _] =
133*9e3b08aeSAndroid Build Coastguard Worker types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
134*9e3b08aeSAndroid Build Coastguard Worker if (x.definition) {
135*9e3b08aeSAndroid Build Coastguard Worker it->second = TypeFidelity::FULLY_DEFINED;
136*9e3b08aeSAndroid Build Coastguard Worker }
137*9e3b08aeSAndroid Build Coastguard Worker }
138*9e3b08aeSAndroid Build Coastguard Worker if (x.definition) {
139*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.definition->base_classes);
140*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.definition->methods);
141*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.definition->members);
142*9e3b08aeSAndroid Build Coastguard Worker }
143*9e3b08aeSAndroid Build Coastguard Worker }
144*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Enumeration & x,Id id)145*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Enumeration& x, Id id) {
146*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty()) {
147*9e3b08aeSAndroid Build Coastguard Worker auto [it, _] =
148*9e3b08aeSAndroid Build Coastguard Worker types.emplace(describe(id).ToString(), TypeFidelity::DECLARATION_ONLY);
149*9e3b08aeSAndroid Build Coastguard Worker if (x.definition) {
150*9e3b08aeSAndroid Build Coastguard Worker it->second = TypeFidelity::FULLY_DEFINED;
151*9e3b08aeSAndroid Build Coastguard Worker }
152*9e3b08aeSAndroid Build Coastguard Worker }
153*9e3b08aeSAndroid Build Coastguard Worker }
154*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Variant & x,Id id)155*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Variant& x, Id id) {
156*9e3b08aeSAndroid Build Coastguard Worker types.emplace(describe(id).ToString(), TypeFidelity::FULLY_DEFINED);
157*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.members);
158*9e3b08aeSAndroid Build Coastguard Worker }
159*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Function & x,Id)160*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Function& x, Id) {
161*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.return_type_id);
162*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.parameters);
163*9e3b08aeSAndroid Build Coastguard Worker }
164*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const ElfSymbol & x,Id)165*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const ElfSymbol& x, Id) {
166*9e3b08aeSAndroid Build Coastguard Worker auto symbol = VersionedSymbolName(x);
167*9e3b08aeSAndroid Build Coastguard Worker auto [it, _] = symbols.emplace(symbol, SymbolFidelity::UNTYPED);
168*9e3b08aeSAndroid Build Coastguard Worker if (x.type_id) {
169*9e3b08aeSAndroid Build Coastguard Worker it->second = SymbolFidelity::TYPED;
170*9e3b08aeSAndroid Build Coastguard Worker (*this)(*x.type_id);
171*9e3b08aeSAndroid Build Coastguard Worker }
172*9e3b08aeSAndroid Build Coastguard Worker }
173*9e3b08aeSAndroid Build Coastguard Worker
operator ()(const Interface & x,Id)174*9e3b08aeSAndroid Build Coastguard Worker void Fidelity::operator()(const Interface& x, Id) {
175*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.symbols);
176*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.types);
177*9e3b08aeSAndroid Build Coastguard Worker }
178*9e3b08aeSAndroid Build Coastguard Worker
179*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
GetKeys(const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)180*9e3b08aeSAndroid Build Coastguard Worker std::set<std::string> GetKeys(
181*9e3b08aeSAndroid Build Coastguard Worker const std::unordered_map<std::string, T>& x1,
182*9e3b08aeSAndroid Build Coastguard Worker const std::unordered_map<std::string, T>& x2) {
183*9e3b08aeSAndroid Build Coastguard Worker std::set<std::string> keys;
184*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [key, _] : x1) {
185*9e3b08aeSAndroid Build Coastguard Worker keys.insert(key);
186*9e3b08aeSAndroid Build Coastguard Worker }
187*9e3b08aeSAndroid Build Coastguard Worker for (const auto& [key, _] : x2) {
188*9e3b08aeSAndroid Build Coastguard Worker keys.insert(key);
189*9e3b08aeSAndroid Build Coastguard Worker }
190*9e3b08aeSAndroid Build Coastguard Worker return keys;
191*9e3b08aeSAndroid Build Coastguard Worker }
192*9e3b08aeSAndroid Build Coastguard Worker
InsertTransition(FidelityDiff & diff,SymbolFidelityTransition transition,const std::string & symbol)193*9e3b08aeSAndroid Build Coastguard Worker void InsertTransition(FidelityDiff& diff, SymbolFidelityTransition transition,
194*9e3b08aeSAndroid Build Coastguard Worker const std::string& symbol) {
195*9e3b08aeSAndroid Build Coastguard Worker diff.symbol_transitions[transition].push_back(symbol);
196*9e3b08aeSAndroid Build Coastguard Worker }
197*9e3b08aeSAndroid Build Coastguard Worker
InsertTransition(FidelityDiff & diff,TypeFidelityTransition transition,const std::string & type)198*9e3b08aeSAndroid Build Coastguard Worker void InsertTransition(FidelityDiff& diff, TypeFidelityTransition transition,
199*9e3b08aeSAndroid Build Coastguard Worker const std::string& type) {
200*9e3b08aeSAndroid Build Coastguard Worker diff.type_transitions[transition].push_back(type);
201*9e3b08aeSAndroid Build Coastguard Worker }
202*9e3b08aeSAndroid Build Coastguard Worker
203*9e3b08aeSAndroid Build Coastguard Worker template <typename T>
InsertTransitions(FidelityDiff & diff,const std::unordered_map<std::string,T> & x1,const std::unordered_map<std::string,T> & x2)204*9e3b08aeSAndroid Build Coastguard Worker void InsertTransitions(FidelityDiff& diff,
205*9e3b08aeSAndroid Build Coastguard Worker const std::unordered_map<std::string, T>& x1,
206*9e3b08aeSAndroid Build Coastguard Worker const std::unordered_map<std::string, T>& x2) {
207*9e3b08aeSAndroid Build Coastguard Worker for (const auto& key : GetKeys(x1, x2)) {
208*9e3b08aeSAndroid Build Coastguard Worker auto it1 = x1.find(key);
209*9e3b08aeSAndroid Build Coastguard Worker auto it2 = x2.find(key);
210*9e3b08aeSAndroid Build Coastguard Worker auto transition = std::make_pair(it1 == x1.end() ? T() : it1->second,
211*9e3b08aeSAndroid Build Coastguard Worker it2 == x2.end() ? T() : it2->second);
212*9e3b08aeSAndroid Build Coastguard Worker InsertTransition(diff, transition, key);
213*9e3b08aeSAndroid Build Coastguard Worker }
214*9e3b08aeSAndroid Build Coastguard Worker }
215*9e3b08aeSAndroid Build Coastguard Worker
216*9e3b08aeSAndroid Build Coastguard Worker } // namespace
217*9e3b08aeSAndroid Build Coastguard Worker
operator <<(std::ostream & os,SymbolFidelity x)218*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, SymbolFidelity x) {
219*9e3b08aeSAndroid Build Coastguard Worker switch (x) {
220*9e3b08aeSAndroid Build Coastguard Worker case SymbolFidelity::ABSENT:
221*9e3b08aeSAndroid Build Coastguard Worker return os << "ABSENT";
222*9e3b08aeSAndroid Build Coastguard Worker case SymbolFidelity::TYPED:
223*9e3b08aeSAndroid Build Coastguard Worker return os << "TYPED";
224*9e3b08aeSAndroid Build Coastguard Worker case SymbolFidelity::UNTYPED:
225*9e3b08aeSAndroid Build Coastguard Worker return os << "UNTYPED";
226*9e3b08aeSAndroid Build Coastguard Worker }
227*9e3b08aeSAndroid Build Coastguard Worker }
228*9e3b08aeSAndroid Build Coastguard Worker
operator <<(std::ostream & os,TypeFidelity x)229*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, TypeFidelity x) {
230*9e3b08aeSAndroid Build Coastguard Worker switch (x) {
231*9e3b08aeSAndroid Build Coastguard Worker case TypeFidelity::ABSENT:
232*9e3b08aeSAndroid Build Coastguard Worker return os << "ABSENT";
233*9e3b08aeSAndroid Build Coastguard Worker case TypeFidelity::DECLARATION_ONLY:
234*9e3b08aeSAndroid Build Coastguard Worker return os << "DECLARATION_ONLY";
235*9e3b08aeSAndroid Build Coastguard Worker case TypeFidelity::FULLY_DEFINED:
236*9e3b08aeSAndroid Build Coastguard Worker return os << "FULLY_DEFINED";
237*9e3b08aeSAndroid Build Coastguard Worker }
238*9e3b08aeSAndroid Build Coastguard Worker }
239*9e3b08aeSAndroid Build Coastguard Worker
operator <<(std::ostream & os,SymbolFidelityTransition x)240*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, SymbolFidelityTransition x) {
241*9e3b08aeSAndroid Build Coastguard Worker return os << "symbol(s) changed from " << x.first << " to " << x.second;
242*9e3b08aeSAndroid Build Coastguard Worker }
243*9e3b08aeSAndroid Build Coastguard Worker
operator <<(std::ostream & os,TypeFidelityTransition x)244*9e3b08aeSAndroid Build Coastguard Worker std::ostream& operator<<(std::ostream& os, TypeFidelityTransition x) {
245*9e3b08aeSAndroid Build Coastguard Worker return os << "type(s) changed from " << x.first << " to " << x.second;
246*9e3b08aeSAndroid Build Coastguard Worker }
247*9e3b08aeSAndroid Build Coastguard Worker
GetFidelityTransitions(const Graph & graph,Id root1,Id root2)248*9e3b08aeSAndroid Build Coastguard Worker FidelityDiff GetFidelityTransitions(const Graph& graph, Id root1, Id root2) {
249*9e3b08aeSAndroid Build Coastguard Worker NameCache name_cache;
250*9e3b08aeSAndroid Build Coastguard Worker Fidelity fidelity1(graph, name_cache);
251*9e3b08aeSAndroid Build Coastguard Worker Fidelity fidelity2(graph, name_cache);
252*9e3b08aeSAndroid Build Coastguard Worker fidelity1(root1);
253*9e3b08aeSAndroid Build Coastguard Worker fidelity2(root2);
254*9e3b08aeSAndroid Build Coastguard Worker
255*9e3b08aeSAndroid Build Coastguard Worker FidelityDiff diff;
256*9e3b08aeSAndroid Build Coastguard Worker InsertTransitions(diff, fidelity1.symbols, fidelity2.symbols);
257*9e3b08aeSAndroid Build Coastguard Worker InsertTransitions(diff, fidelity1.types, fidelity2.types);
258*9e3b08aeSAndroid Build Coastguard Worker return diff;
259*9e3b08aeSAndroid Build Coastguard Worker }
260*9e3b08aeSAndroid Build Coastguard Worker
261*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg
262