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