xref: /aosp_15_r20/external/stg/equality.h (revision 9e3b08ae94a55201065475453d799e8b1378bea6)
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 2022-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: Giuliano Procida
19*9e3b08aeSAndroid Build Coastguard Worker 
20*9e3b08aeSAndroid Build Coastguard Worker #ifndef STG_EQUALITY_H_
21*9e3b08aeSAndroid Build Coastguard Worker #define STG_EQUALITY_H_
22*9e3b08aeSAndroid Build Coastguard Worker 
23*9e3b08aeSAndroid Build Coastguard Worker #include <cstddef>
24*9e3b08aeSAndroid Build Coastguard Worker #include <map>
25*9e3b08aeSAndroid Build Coastguard Worker #include <optional>
26*9e3b08aeSAndroid Build Coastguard Worker #include <vector>
27*9e3b08aeSAndroid Build Coastguard Worker 
28*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h"
29*9e3b08aeSAndroid Build Coastguard Worker #include "scc.h"
30*9e3b08aeSAndroid Build Coastguard Worker 
31*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
32*9e3b08aeSAndroid Build Coastguard Worker 
33*9e3b08aeSAndroid Build Coastguard Worker // Node equality algorithm. This only cares about node and edge attributes and
34*9e3b08aeSAndroid Build Coastguard Worker // is blind to node identity. It is generic over the equality cache which is fed
35*9e3b08aeSAndroid Build Coastguard Worker // information about equality results and queried for the same. Different
36*9e3b08aeSAndroid Build Coastguard Worker // implementations are possible depending on the needs of the caller and the
37*9e3b08aeSAndroid Build Coastguard Worker // guaranteed invariants.
38*9e3b08aeSAndroid Build Coastguard Worker template <typename EqualityCache>
39*9e3b08aeSAndroid Build Coastguard Worker struct Equals {
EqualsEquals40*9e3b08aeSAndroid Build Coastguard Worker   Equals(const Graph& graph, EqualityCache& equality_cache)
41*9e3b08aeSAndroid Build Coastguard Worker       : graph(graph), equality_cache(equality_cache) {}
42*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals43*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(Id id1, Id id2) {
44*9e3b08aeSAndroid Build Coastguard Worker     const Pair comparison = {id1, id2};
45*9e3b08aeSAndroid Build Coastguard Worker 
46*9e3b08aeSAndroid Build Coastguard Worker     // Check if the comparison has an already known result.
47*9e3b08aeSAndroid Build Coastguard Worker     const auto check = equality_cache.Query(comparison);
48*9e3b08aeSAndroid Build Coastguard Worker     if (check.has_value()) {
49*9e3b08aeSAndroid Build Coastguard Worker       return check.value();
50*9e3b08aeSAndroid Build Coastguard Worker     }
51*9e3b08aeSAndroid Build Coastguard Worker 
52*9e3b08aeSAndroid Build Coastguard Worker     // Record the comparison with Strongly-Connected Component finder.
53*9e3b08aeSAndroid Build Coastguard Worker     auto handle = scc.Open(comparison);
54*9e3b08aeSAndroid Build Coastguard Worker     if (!handle) {
55*9e3b08aeSAndroid Build Coastguard Worker       // Already open.
56*9e3b08aeSAndroid Build Coastguard Worker       //
57*9e3b08aeSAndroid Build Coastguard Worker       // Return a dummy true outcome.
58*9e3b08aeSAndroid Build Coastguard Worker       return true;
59*9e3b08aeSAndroid Build Coastguard Worker     }
60*9e3b08aeSAndroid Build Coastguard Worker     // Comparison opened, need to close it before returning.
61*9e3b08aeSAndroid Build Coastguard Worker 
62*9e3b08aeSAndroid Build Coastguard Worker     const auto result = graph.Apply2(*this, id1, id2);
63*9e3b08aeSAndroid Build Coastguard Worker 
64*9e3b08aeSAndroid Build Coastguard Worker     // Check for a complete Strongly-Connected Component.
65*9e3b08aeSAndroid Build Coastguard Worker     auto comparisons = scc.Close(*handle);
66*9e3b08aeSAndroid Build Coastguard Worker     if (comparisons.empty()) {
67*9e3b08aeSAndroid Build Coastguard Worker       // Note that result is tentative as the SCC is still open.
68*9e3b08aeSAndroid Build Coastguard Worker       return result;
69*9e3b08aeSAndroid Build Coastguard Worker     }
70*9e3b08aeSAndroid Build Coastguard Worker 
71*9e3b08aeSAndroid Build Coastguard Worker     // Closed SCC.
72*9e3b08aeSAndroid Build Coastguard Worker     //
73*9e3b08aeSAndroid Build Coastguard Worker     // Note that result is the conjunction of every equality in the SCC via the
74*9e3b08aeSAndroid Build Coastguard Worker     // DFS spanning tree.
75*9e3b08aeSAndroid Build Coastguard Worker     if (result) {
76*9e3b08aeSAndroid Build Coastguard Worker       equality_cache.AllSame(comparisons);
77*9e3b08aeSAndroid Build Coastguard Worker     } else {
78*9e3b08aeSAndroid Build Coastguard Worker       equality_cache.AllDifferent(comparisons);
79*9e3b08aeSAndroid Build Coastguard Worker     }
80*9e3b08aeSAndroid Build Coastguard Worker     return result;
81*9e3b08aeSAndroid Build Coastguard Worker   }
82*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals83*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const std::optional<Id>& opt1,
84*9e3b08aeSAndroid Build Coastguard Worker                   const std::optional<Id>& opt2) {
85*9e3b08aeSAndroid Build Coastguard Worker     if (opt1.has_value() && opt2.has_value()) {
86*9e3b08aeSAndroid Build Coastguard Worker       return (*this)(opt1.value(), opt2.value());
87*9e3b08aeSAndroid Build Coastguard Worker     }
88*9e3b08aeSAndroid Build Coastguard Worker     return opt1.has_value() == opt2.has_value();
89*9e3b08aeSAndroid Build Coastguard Worker   }
90*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals91*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const std::vector<Id>& ids1, const std::vector<Id>& ids2) {
92*9e3b08aeSAndroid Build Coastguard Worker     bool result = ids1.size() == ids2.size();
93*9e3b08aeSAndroid Build Coastguard Worker     for (size_t ix = 0; result && ix < ids1.size(); ++ix) {
94*9e3b08aeSAndroid Build Coastguard Worker       result = (*this)(ids1[ix], ids2[ix]);
95*9e3b08aeSAndroid Build Coastguard Worker     }
96*9e3b08aeSAndroid Build Coastguard Worker     return result;
97*9e3b08aeSAndroid Build Coastguard Worker   }
98*9e3b08aeSAndroid Build Coastguard Worker 
99*9e3b08aeSAndroid Build Coastguard Worker   template <typename Key>
operatorEquals100*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const std::map<Key, Id>& ids1,
101*9e3b08aeSAndroid Build Coastguard Worker                   const std::map<Key, Id>& ids2) {
102*9e3b08aeSAndroid Build Coastguard Worker     bool result = ids1.size() == ids2.size();
103*9e3b08aeSAndroid Build Coastguard Worker     auto it1 = ids1.begin();
104*9e3b08aeSAndroid Build Coastguard Worker     auto it2 = ids2.begin();
105*9e3b08aeSAndroid Build Coastguard Worker     const auto end1 = ids1.end();
106*9e3b08aeSAndroid Build Coastguard Worker     const auto end2 = ids2.end();
107*9e3b08aeSAndroid Build Coastguard Worker     while (result && it1 != end1 && it2 != end2) {
108*9e3b08aeSAndroid Build Coastguard Worker       result = it1->first == it2->first
109*9e3b08aeSAndroid Build Coastguard Worker                && (*this)(it1->second, it2->second);
110*9e3b08aeSAndroid Build Coastguard Worker       ++it1;
111*9e3b08aeSAndroid Build Coastguard Worker       ++it2;
112*9e3b08aeSAndroid Build Coastguard Worker     }
113*9e3b08aeSAndroid Build Coastguard Worker     return result && it1 == end1 && it2 == end2;
114*9e3b08aeSAndroid Build Coastguard Worker   }
115*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals116*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Special& x1, const Special& x2) {
117*9e3b08aeSAndroid Build Coastguard Worker     return x1.kind == x2.kind;
118*9e3b08aeSAndroid Build Coastguard Worker   }
119*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals120*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const PointerReference& x1,
121*9e3b08aeSAndroid Build Coastguard Worker                   const PointerReference& x2) {
122*9e3b08aeSAndroid Build Coastguard Worker     return x1.kind == x2.kind
123*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.pointee_type_id, x2.pointee_type_id);
124*9e3b08aeSAndroid Build Coastguard Worker   }
125*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals126*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const PointerToMember& x1, const PointerToMember& x2) {
127*9e3b08aeSAndroid Build Coastguard Worker     return (*this)(x1.containing_type_id, x2.containing_type_id)
128*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.pointee_type_id, x2.pointee_type_id);
129*9e3b08aeSAndroid Build Coastguard Worker   }
130*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals131*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Typedef& x1, const Typedef& x2) {
132*9e3b08aeSAndroid Build Coastguard Worker     return x1.name == x2.name
133*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.referred_type_id, x2.referred_type_id);
134*9e3b08aeSAndroid Build Coastguard Worker   }
135*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals136*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Qualified& x1, const Qualified& x2) {
137*9e3b08aeSAndroid Build Coastguard Worker     return x1.qualifier == x2.qualifier
138*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.qualified_type_id, x2.qualified_type_id);
139*9e3b08aeSAndroid Build Coastguard Worker   }
140*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals141*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Primitive& x1, const Primitive& x2) {
142*9e3b08aeSAndroid Build Coastguard Worker     return x1.name == x2.name
143*9e3b08aeSAndroid Build Coastguard Worker         && x1.encoding == x2.encoding
144*9e3b08aeSAndroid Build Coastguard Worker         && x1.bytesize == x2.bytesize;
145*9e3b08aeSAndroid Build Coastguard Worker   }
146*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals147*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Array& x1, const Array& x2) {
148*9e3b08aeSAndroid Build Coastguard Worker     return x1.number_of_elements == x2.number_of_elements
149*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.element_type_id, x2.element_type_id);
150*9e3b08aeSAndroid Build Coastguard Worker   }
151*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals152*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const BaseClass& x1, const BaseClass& x2) {
153*9e3b08aeSAndroid Build Coastguard Worker     return x1.offset == x2.offset
154*9e3b08aeSAndroid Build Coastguard Worker         && x1.inheritance == x2.inheritance
155*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.type_id, x2.type_id);
156*9e3b08aeSAndroid Build Coastguard Worker   }
157*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals158*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Method& x1, const Method& x2) {
159*9e3b08aeSAndroid Build Coastguard Worker     return x1.mangled_name == x2.mangled_name
160*9e3b08aeSAndroid Build Coastguard Worker         && x1.name == x2.name
161*9e3b08aeSAndroid Build Coastguard Worker         && x1.vtable_offset == x2.vtable_offset
162*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.type_id, x2.type_id);
163*9e3b08aeSAndroid Build Coastguard Worker   }
164*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals165*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Member& x1, const Member& x2) {
166*9e3b08aeSAndroid Build Coastguard Worker     return x1.name == x2.name
167*9e3b08aeSAndroid Build Coastguard Worker         && x1.offset == x2.offset
168*9e3b08aeSAndroid Build Coastguard Worker         && x1.bitsize == x2.bitsize
169*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.type_id, x2.type_id);
170*9e3b08aeSAndroid Build Coastguard Worker   }
171*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals172*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const VariantMember& x1, const VariantMember& x2) {
173*9e3b08aeSAndroid Build Coastguard Worker     return x1.name == x2.name
174*9e3b08aeSAndroid Build Coastguard Worker         && x1.discriminant_value == x2.discriminant_value
175*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.type_id, x2.type_id);
176*9e3b08aeSAndroid Build Coastguard Worker   }
177*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals178*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const StructUnion& x1, const StructUnion& x2) {
179*9e3b08aeSAndroid Build Coastguard Worker     const auto& definition1 = x1.definition;
180*9e3b08aeSAndroid Build Coastguard Worker     const auto& definition2 = x2.definition;
181*9e3b08aeSAndroid Build Coastguard Worker     bool result = x1.kind == x2.kind
182*9e3b08aeSAndroid Build Coastguard Worker                   && x1.name == x2.name
183*9e3b08aeSAndroid Build Coastguard Worker                   && definition1.has_value() == definition2.has_value();
184*9e3b08aeSAndroid Build Coastguard Worker     if (result && definition1.has_value()) {
185*9e3b08aeSAndroid Build Coastguard Worker       result = definition1->bytesize == definition2->bytesize
186*9e3b08aeSAndroid Build Coastguard Worker                && (*this)(definition1->base_classes, definition2->base_classes)
187*9e3b08aeSAndroid Build Coastguard Worker                && (*this)(definition1->methods, definition2->methods)
188*9e3b08aeSAndroid Build Coastguard Worker                && (*this)(definition1->members, definition2->members);
189*9e3b08aeSAndroid Build Coastguard Worker     }
190*9e3b08aeSAndroid Build Coastguard Worker     return result;
191*9e3b08aeSAndroid Build Coastguard Worker   }
192*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals193*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Enumeration& x1, const Enumeration& x2) {
194*9e3b08aeSAndroid Build Coastguard Worker     const auto& definition1 = x1.definition;
195*9e3b08aeSAndroid Build Coastguard Worker     const auto& definition2 = x2.definition;
196*9e3b08aeSAndroid Build Coastguard Worker     bool result = x1.name == x2.name
197*9e3b08aeSAndroid Build Coastguard Worker                   && definition1.has_value() == definition2.has_value();
198*9e3b08aeSAndroid Build Coastguard Worker     if (result && definition1.has_value()) {
199*9e3b08aeSAndroid Build Coastguard Worker       result = (*this)(definition1->underlying_type_id,
200*9e3b08aeSAndroid Build Coastguard Worker                        definition2->underlying_type_id)
201*9e3b08aeSAndroid Build Coastguard Worker                && definition1->enumerators == definition2->enumerators;
202*9e3b08aeSAndroid Build Coastguard Worker     }
203*9e3b08aeSAndroid Build Coastguard Worker     return result;
204*9e3b08aeSAndroid Build Coastguard Worker   }
205*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals206*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Variant& x1, const Variant& x2) {
207*9e3b08aeSAndroid Build Coastguard Worker     return x1.name == x2.name
208*9e3b08aeSAndroid Build Coastguard Worker         && x1.bytesize == x2.bytesize
209*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.discriminant, x2.discriminant)
210*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.members, x2.members);
211*9e3b08aeSAndroid Build Coastguard Worker   }
212*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals213*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Function& x1, const Function& x2) {
214*9e3b08aeSAndroid Build Coastguard Worker     return (*this)(x1.parameters, x2.parameters)
215*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.return_type_id, x2.return_type_id);
216*9e3b08aeSAndroid Build Coastguard Worker   }
217*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals218*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const ElfSymbol& x1, const ElfSymbol& x2) {
219*9e3b08aeSAndroid Build Coastguard Worker     bool result = x1.symbol_name == x2.symbol_name
220*9e3b08aeSAndroid Build Coastguard Worker                   && x1.version_info == x2.version_info
221*9e3b08aeSAndroid Build Coastguard Worker                   && x1.is_defined == x2.is_defined
222*9e3b08aeSAndroid Build Coastguard Worker                   && x1.symbol_type == x2.symbol_type
223*9e3b08aeSAndroid Build Coastguard Worker                   && x1.binding == x2.binding
224*9e3b08aeSAndroid Build Coastguard Worker                   && x1.visibility == x2.visibility
225*9e3b08aeSAndroid Build Coastguard Worker                   && x1.crc == x2.crc
226*9e3b08aeSAndroid Build Coastguard Worker                   && x1.ns == x2.ns
227*9e3b08aeSAndroid Build Coastguard Worker                   && x1.full_name == x2.full_name
228*9e3b08aeSAndroid Build Coastguard Worker                   && x1.type_id.has_value() == x2.type_id.has_value();
229*9e3b08aeSAndroid Build Coastguard Worker     if (result && x1.type_id.has_value()) {
230*9e3b08aeSAndroid Build Coastguard Worker       result = (*this)(x1.type_id.value(), x2.type_id.value());
231*9e3b08aeSAndroid Build Coastguard Worker     }
232*9e3b08aeSAndroid Build Coastguard Worker     return result;
233*9e3b08aeSAndroid Build Coastguard Worker   }
234*9e3b08aeSAndroid Build Coastguard Worker 
operatorEquals235*9e3b08aeSAndroid Build Coastguard Worker   bool operator()(const Interface& x1, const Interface& x2) {
236*9e3b08aeSAndroid Build Coastguard Worker     return (*this)(x1.symbols, x2.symbols)
237*9e3b08aeSAndroid Build Coastguard Worker         && (*this)(x1.types, x2.types);
238*9e3b08aeSAndroid Build Coastguard Worker   }
239*9e3b08aeSAndroid Build Coastguard Worker 
MismatchEquals240*9e3b08aeSAndroid Build Coastguard Worker   bool Mismatch() {
241*9e3b08aeSAndroid Build Coastguard Worker     return false;
242*9e3b08aeSAndroid Build Coastguard Worker   }
243*9e3b08aeSAndroid Build Coastguard Worker 
244*9e3b08aeSAndroid Build Coastguard Worker   const Graph& graph;
245*9e3b08aeSAndroid Build Coastguard Worker   EqualityCache& equality_cache;
246*9e3b08aeSAndroid Build Coastguard Worker   SCC<Pair> scc;
247*9e3b08aeSAndroid Build Coastguard Worker };
248*9e3b08aeSAndroid Build Coastguard Worker 
249*9e3b08aeSAndroid Build Coastguard Worker }  // namespace stg
250*9e3b08aeSAndroid Build Coastguard Worker 
251*9e3b08aeSAndroid Build Coastguard Worker #endif  // STG_EQUALITY_H_
252