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: Siddharth Nayyar
19*9e3b08aeSAndroid Build Coastguard Worker
20*9e3b08aeSAndroid Build Coastguard Worker #include "stable_hash.h"
21*9e3b08aeSAndroid Build Coastguard Worker
22*9e3b08aeSAndroid Build Coastguard Worker #include <cstdint>
23*9e3b08aeSAndroid Build Coastguard Worker #include <string>
24*9e3b08aeSAndroid Build Coastguard Worker #include <unordered_map>
25*9e3b08aeSAndroid Build Coastguard Worker #include <utility>
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 "hashing.h"
30*9e3b08aeSAndroid Build Coastguard Worker
31*9e3b08aeSAndroid Build Coastguard Worker namespace stg {
32*9e3b08aeSAndroid Build Coastguard Worker
33*9e3b08aeSAndroid Build Coastguard Worker namespace {
34*9e3b08aeSAndroid Build Coastguard Worker
35*9e3b08aeSAndroid Build Coastguard Worker // This combines 2 hash values while decaying (by shifting right) the second
36*9e3b08aeSAndroid Build Coastguard Worker // value. This prevents the most significant bits of the first hash from being
37*9e3b08aeSAndroid Build Coastguard Worker // affected by the decayed hash. Hash combination is done using a simple XOR
38*9e3b08aeSAndroid Build Coastguard Worker // operation to preserve the separation of higher and lower bits. Note that XOR
39*9e3b08aeSAndroid Build Coastguard Worker // is not a very effective method of mixing hash values if the values are
40*9e3b08aeSAndroid Build Coastguard Worker // generated with a weak hashing algorithm.
41*9e3b08aeSAndroid Build Coastguard Worker template <uint8_t decay>
DecayHashCombine(HashValue a,HashValue b)42*9e3b08aeSAndroid Build Coastguard Worker constexpr HashValue DecayHashCombine(HashValue a, HashValue b) {
43*9e3b08aeSAndroid Build Coastguard Worker static_assert(decay > 0 && decay < 32, "decay must lie inside (0, 32)");
44*9e3b08aeSAndroid Build Coastguard Worker return HashValue(a.value ^ (b.value >> decay));
45*9e3b08aeSAndroid Build Coastguard Worker }
46*9e3b08aeSAndroid Build Coastguard Worker
47*9e3b08aeSAndroid Build Coastguard Worker // Decaying hashes are combined in reverse since the each successive hashable
48*9e3b08aeSAndroid Build Coastguard Worker // should be decayed 1 more time than the previous hashable and the last
49*9e3b08aeSAndroid Build Coastguard Worker // hashable should receieve the most decay.
50*9e3b08aeSAndroid Build Coastguard Worker template <uint8_t decay, typename Type, typename Hash>
DecayHashCombineInReverse(const std::vector<Type> & hashables,Hash & hash)51*9e3b08aeSAndroid Build Coastguard Worker HashValue DecayHashCombineInReverse(const std::vector<Type>& hashables,
52*9e3b08aeSAndroid Build Coastguard Worker Hash& hash) {
53*9e3b08aeSAndroid Build Coastguard Worker HashValue result(0);
54*9e3b08aeSAndroid Build Coastguard Worker for (auto it = hashables.crbegin(); it != hashables.crend(); ++it) {
55*9e3b08aeSAndroid Build Coastguard Worker result = DecayHashCombine<decay>(hash(*it), result);
56*9e3b08aeSAndroid Build Coastguard Worker }
57*9e3b08aeSAndroid Build Coastguard Worker return result;
58*9e3b08aeSAndroid Build Coastguard Worker }
59*9e3b08aeSAndroid Build Coastguard Worker
60*9e3b08aeSAndroid Build Coastguard Worker struct StableHashWorker {
StableHashWorkerstg::__anon9c7ff0960111::StableHashWorker61*9e3b08aeSAndroid Build Coastguard Worker StableHashWorker(const Graph& graph, std::unordered_map<Id, HashValue>& cache)
62*9e3b08aeSAndroid Build Coastguard Worker : graph(graph), cache(cache) {}
63*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker64*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(Id id) {
65*9e3b08aeSAndroid Build Coastguard Worker auto [it, inserted] = cache.emplace(id, 0);
66*9e3b08aeSAndroid Build Coastguard Worker if (inserted) {
67*9e3b08aeSAndroid Build Coastguard Worker it->second = graph.Apply(*this, id);
68*9e3b08aeSAndroid Build Coastguard Worker }
69*9e3b08aeSAndroid Build Coastguard Worker return it->second;
70*9e3b08aeSAndroid Build Coastguard Worker }
71*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker72*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Special& x) {
73*9e3b08aeSAndroid Build Coastguard Worker switch (x.kind) {
74*9e3b08aeSAndroid Build Coastguard Worker case Special::Kind::VOID:
75*9e3b08aeSAndroid Build Coastguard Worker return hash("void");
76*9e3b08aeSAndroid Build Coastguard Worker case Special::Kind::VARIADIC:
77*9e3b08aeSAndroid Build Coastguard Worker return hash("variadic");
78*9e3b08aeSAndroid Build Coastguard Worker case Special::Kind::NULLPTR:
79*9e3b08aeSAndroid Build Coastguard Worker return hash("nullptr");
80*9e3b08aeSAndroid Build Coastguard Worker }
81*9e3b08aeSAndroid Build Coastguard Worker }
82*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker83*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const PointerReference& x) {
84*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(hash('r', static_cast<uint32_t>(x.kind)),
85*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.pointee_type_id));
86*9e3b08aeSAndroid Build Coastguard Worker }
87*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker88*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const PointerToMember& x) {
89*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<16>(hash('n', (*this)(x.containing_type_id)),
90*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.pointee_type_id));
91*9e3b08aeSAndroid Build Coastguard Worker }
92*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker93*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Typedef& x) {
94*9e3b08aeSAndroid Build Coastguard Worker return hash('t', x.name);
95*9e3b08aeSAndroid Build Coastguard Worker }
96*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker97*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Qualified& x) {
98*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(hash('q', static_cast<uint32_t>(x.qualifier)),
99*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.qualified_type_id));
100*9e3b08aeSAndroid Build Coastguard Worker }
101*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker102*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Primitive& x) {
103*9e3b08aeSAndroid Build Coastguard Worker return hash('p', x.name);
104*9e3b08aeSAndroid Build Coastguard Worker }
105*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker106*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Array& x) {
107*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(hash('a', x.number_of_elements),
108*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.element_type_id));
109*9e3b08aeSAndroid Build Coastguard Worker }
110*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker111*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const BaseClass& x) {
112*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(hash('b', static_cast<uint32_t>(x.inheritance)),
113*9e3b08aeSAndroid Build Coastguard Worker (*this)(x.type_id));
114*9e3b08aeSAndroid Build Coastguard Worker }
115*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker116*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Method& x) {
117*9e3b08aeSAndroid Build Coastguard Worker return hash(x.mangled_name);
118*9e3b08aeSAndroid Build Coastguard Worker }
119*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker120*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Member& x) {
121*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('m', x.name, x.bitsize);
122*9e3b08aeSAndroid Build Coastguard Worker value = DecayHashCombine<20>(value, hash(x.offset));
123*9e3b08aeSAndroid Build Coastguard Worker if (x.name.empty()) {
124*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(value, (*this)(x.type_id));
125*9e3b08aeSAndroid Build Coastguard Worker } else {
126*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<8>(value, (*this)(x.type_id));
127*9e3b08aeSAndroid Build Coastguard Worker }
128*9e3b08aeSAndroid Build Coastguard Worker }
129*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker130*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const VariantMember& x) {
131*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('v', x.name);
132*9e3b08aeSAndroid Build Coastguard Worker value = DecayHashCombine<8>(value, (*this)(x.type_id));
133*9e3b08aeSAndroid Build Coastguard Worker return x.discriminant_value
134*9e3b08aeSAndroid Build Coastguard Worker ? DecayHashCombine<20>(value, hash(*x.discriminant_value))
135*9e3b08aeSAndroid Build Coastguard Worker : value;
136*9e3b08aeSAndroid Build Coastguard Worker }
137*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker138*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const StructUnion& x) {
139*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('S', static_cast<uint32_t>(x.kind), x.name,
140*9e3b08aeSAndroid Build Coastguard Worker static_cast<bool>(x.definition));
141*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty() || !x.definition) {
142*9e3b08aeSAndroid Build Coastguard Worker return value;
143*9e3b08aeSAndroid Build Coastguard Worker }
144*9e3b08aeSAndroid Build Coastguard Worker
145*9e3b08aeSAndroid Build Coastguard Worker auto h1 = DecayHashCombineInReverse<8>(x.definition->methods, *this);
146*9e3b08aeSAndroid Build Coastguard Worker auto h2 = DecayHashCombineInReverse<8>(x.definition->members, *this);
147*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(value, HashValue(h1.value ^ h2.value));
148*9e3b08aeSAndroid Build Coastguard Worker }
149*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker150*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Enumeration& x) {
151*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('e', x.name, static_cast<bool>(x.definition));
152*9e3b08aeSAndroid Build Coastguard Worker if (!x.name.empty() || !x.definition) {
153*9e3b08aeSAndroid Build Coastguard Worker return value;
154*9e3b08aeSAndroid Build Coastguard Worker }
155*9e3b08aeSAndroid Build Coastguard Worker
156*9e3b08aeSAndroid Build Coastguard Worker auto hash_enum = [this](const std::pair<std::string, int64_t>& e) {
157*9e3b08aeSAndroid Build Coastguard Worker return hash(e.first, e.second);
158*9e3b08aeSAndroid Build Coastguard Worker };
159*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(value, DecayHashCombineInReverse<8>(
160*9e3b08aeSAndroid Build Coastguard Worker x.definition->enumerators, hash_enum));
161*9e3b08aeSAndroid Build Coastguard Worker }
162*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker163*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Variant& x) {
164*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('V', x.name, x.bytesize);
165*9e3b08aeSAndroid Build Coastguard Worker if (x.discriminant.has_value()) {
166*9e3b08aeSAndroid Build Coastguard Worker value = DecayHashCombine<12>(value, (*this)(x.discriminant.value()));
167*9e3b08aeSAndroid Build Coastguard Worker }
168*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(value,
169*9e3b08aeSAndroid Build Coastguard Worker DecayHashCombineInReverse<8>(x.members, *this));
170*9e3b08aeSAndroid Build Coastguard Worker }
171*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker172*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Function& x) {
173*9e3b08aeSAndroid Build Coastguard Worker return DecayHashCombine<2>(
174*9e3b08aeSAndroid Build Coastguard Worker hash('f', (*this)(x.return_type_id)),
175*9e3b08aeSAndroid Build Coastguard Worker DecayHashCombineInReverse<4>(x.parameters, *this));
176*9e3b08aeSAndroid Build Coastguard Worker }
177*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker178*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const ElfSymbol& x) {
179*9e3b08aeSAndroid Build Coastguard Worker HashValue value = hash('s', x.symbol_name);
180*9e3b08aeSAndroid Build Coastguard Worker if (x.version_info) {
181*9e3b08aeSAndroid Build Coastguard Worker value = DecayHashCombine<16>(
182*9e3b08aeSAndroid Build Coastguard Worker value, hash(x.version_info->name, x.version_info->is_default));
183*9e3b08aeSAndroid Build Coastguard Worker }
184*9e3b08aeSAndroid Build Coastguard Worker return value;
185*9e3b08aeSAndroid Build Coastguard Worker }
186*9e3b08aeSAndroid Build Coastguard Worker
operator ()stg::__anon9c7ff0960111::StableHashWorker187*9e3b08aeSAndroid Build Coastguard Worker HashValue operator()(const Interface&) {
188*9e3b08aeSAndroid Build Coastguard Worker return hash("interface");
189*9e3b08aeSAndroid Build Coastguard Worker }
190*9e3b08aeSAndroid Build Coastguard Worker
191*9e3b08aeSAndroid Build Coastguard Worker const Hash hash;
192*9e3b08aeSAndroid Build Coastguard Worker const Graph& graph;
193*9e3b08aeSAndroid Build Coastguard Worker std::unordered_map<Id, HashValue>& cache;
194*9e3b08aeSAndroid Build Coastguard Worker };
195*9e3b08aeSAndroid Build Coastguard Worker
196*9e3b08aeSAndroid Build Coastguard Worker } // namespace
197*9e3b08aeSAndroid Build Coastguard Worker
operator ()(Id id)198*9e3b08aeSAndroid Build Coastguard Worker HashValue StableHash::operator()(Id id) {
199*9e3b08aeSAndroid Build Coastguard Worker return StableHashWorker(graph_, cache_)(id);
200*9e3b08aeSAndroid Build Coastguard Worker }
201*9e3b08aeSAndroid Build Coastguard Worker
202*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg
203