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-2023 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_UNIFICATION_H_ 21*9e3b08aeSAndroid Build Coastguard Worker #define STG_UNIFICATION_H_ 22*9e3b08aeSAndroid Build Coastguard Worker 23*9e3b08aeSAndroid Build Coastguard Worker #include <exception> 24*9e3b08aeSAndroid Build Coastguard Worker 25*9e3b08aeSAndroid Build Coastguard Worker #include "graph.h" 26*9e3b08aeSAndroid Build Coastguard Worker #include "runtime.h" 27*9e3b08aeSAndroid Build Coastguard Worker #include "substitution.h" 28*9e3b08aeSAndroid Build Coastguard Worker 29*9e3b08aeSAndroid Build Coastguard Worker namespace stg { 30*9e3b08aeSAndroid Build Coastguard Worker 31*9e3b08aeSAndroid Build Coastguard Worker // Keep track of which nodes are pending substitution and rewrite the graph on 32*9e3b08aeSAndroid Build Coastguard Worker // destruction. 33*9e3b08aeSAndroid Build Coastguard Worker class Unification { 34*9e3b08aeSAndroid Build Coastguard Worker public: Unification(Runtime & runtime,Graph & graph,Id start)35*9e3b08aeSAndroid Build Coastguard Worker Unification(Runtime& runtime, Graph& graph, Id start) 36*9e3b08aeSAndroid Build Coastguard Worker : graph_(graph), 37*9e3b08aeSAndroid Build Coastguard Worker start_(start), 38*9e3b08aeSAndroid Build Coastguard Worker mapping_(start), 39*9e3b08aeSAndroid Build Coastguard Worker runtime_(runtime), 40*9e3b08aeSAndroid Build Coastguard Worker find_query_(runtime, "unification.find_query"), 41*9e3b08aeSAndroid Build Coastguard Worker find_halved_(runtime, "unification.find_halved"), 42*9e3b08aeSAndroid Build Coastguard Worker union_known_(runtime, "unification.union_known"), 43*9e3b08aeSAndroid Build Coastguard Worker union_unknown_(runtime, "unification.union_unknown") {} 44*9e3b08aeSAndroid Build Coastguard Worker ~Unification()45*9e3b08aeSAndroid Build Coastguard Worker ~Unification() { 46*9e3b08aeSAndroid Build Coastguard Worker if (std::uncaught_exceptions() > 0) { 47*9e3b08aeSAndroid Build Coastguard Worker // abort unification 48*9e3b08aeSAndroid Build Coastguard Worker return; 49*9e3b08aeSAndroid Build Coastguard Worker } 50*9e3b08aeSAndroid Build Coastguard Worker // apply substitutions to the entire graph 51*9e3b08aeSAndroid Build Coastguard Worker const Time time(runtime_, "unification.rewrite"); 52*9e3b08aeSAndroid Build Coastguard Worker Counter removed(runtime_, "unification.removed"); 53*9e3b08aeSAndroid Build Coastguard Worker Counter retained(runtime_, "unification.retained"); 54*9e3b08aeSAndroid Build Coastguard Worker const auto remap = [&](Id& id) { 55*9e3b08aeSAndroid Build Coastguard Worker Update(id); 56*9e3b08aeSAndroid Build Coastguard Worker }; 57*9e3b08aeSAndroid Build Coastguard Worker const Substitute substitute(graph_, remap); 58*9e3b08aeSAndroid Build Coastguard Worker graph_.ForEach(start_, graph_.Limit(), [&](Id id) { 59*9e3b08aeSAndroid Build Coastguard Worker if (Find(id) != id) { 60*9e3b08aeSAndroid Build Coastguard Worker graph_.Remove(id); 61*9e3b08aeSAndroid Build Coastguard Worker ++removed; 62*9e3b08aeSAndroid Build Coastguard Worker } else { 63*9e3b08aeSAndroid Build Coastguard Worker substitute(id); 64*9e3b08aeSAndroid Build Coastguard Worker ++retained; 65*9e3b08aeSAndroid Build Coastguard Worker } 66*9e3b08aeSAndroid Build Coastguard Worker }); 67*9e3b08aeSAndroid Build Coastguard Worker } 68*9e3b08aeSAndroid Build Coastguard Worker Reserve(Id limit)69*9e3b08aeSAndroid Build Coastguard Worker void Reserve(Id limit) { 70*9e3b08aeSAndroid Build Coastguard Worker mapping_.Reserve(limit); 71*9e3b08aeSAndroid Build Coastguard Worker } 72*9e3b08aeSAndroid Build Coastguard Worker 73*9e3b08aeSAndroid Build Coastguard Worker bool Unify(Id id1, Id id2); 74*9e3b08aeSAndroid Build Coastguard Worker Find(Id id)75*9e3b08aeSAndroid Build Coastguard Worker Id Find(Id id) { 76*9e3b08aeSAndroid Build Coastguard Worker ++find_query_; 77*9e3b08aeSAndroid Build Coastguard Worker // path halving - tiny performance gain 78*9e3b08aeSAndroid Build Coastguard Worker while (true) { 79*9e3b08aeSAndroid Build Coastguard Worker // note: safe to take a reference as mapping cannot grow after this 80*9e3b08aeSAndroid Build Coastguard Worker auto& parent = mapping_[id]; 81*9e3b08aeSAndroid Build Coastguard Worker if (parent == id) { 82*9e3b08aeSAndroid Build Coastguard Worker return id; 83*9e3b08aeSAndroid Build Coastguard Worker } 84*9e3b08aeSAndroid Build Coastguard Worker const auto parent_parent = mapping_[parent]; 85*9e3b08aeSAndroid Build Coastguard Worker if (parent_parent == parent) { 86*9e3b08aeSAndroid Build Coastguard Worker return parent; 87*9e3b08aeSAndroid Build Coastguard Worker } 88*9e3b08aeSAndroid Build Coastguard Worker id = parent = parent_parent; 89*9e3b08aeSAndroid Build Coastguard Worker ++find_halved_; 90*9e3b08aeSAndroid Build Coastguard Worker } 91*9e3b08aeSAndroid Build Coastguard Worker } 92*9e3b08aeSAndroid Build Coastguard Worker Union(Id id1,Id id2)93*9e3b08aeSAndroid Build Coastguard Worker void Union(Id id1, Id id2) { 94*9e3b08aeSAndroid Build Coastguard Worker // id2 will always be preferred as a parent node; interpreted as a 95*9e3b08aeSAndroid Build Coastguard Worker // substitution, id1 will be replaced by id2 96*9e3b08aeSAndroid Build Coastguard Worker const Id fid1 = Find(id1); 97*9e3b08aeSAndroid Build Coastguard Worker const Id fid2 = Find(id2); 98*9e3b08aeSAndroid Build Coastguard Worker if (fid1 == fid2) { 99*9e3b08aeSAndroid Build Coastguard Worker ++union_known_; 100*9e3b08aeSAndroid Build Coastguard Worker return; 101*9e3b08aeSAndroid Build Coastguard Worker } 102*9e3b08aeSAndroid Build Coastguard Worker mapping_[fid1] = fid2; 103*9e3b08aeSAndroid Build Coastguard Worker ++union_unknown_; 104*9e3b08aeSAndroid Build Coastguard Worker } 105*9e3b08aeSAndroid Build Coastguard Worker 106*9e3b08aeSAndroid Build Coastguard Worker // update id to representative id Update(Id & id)107*9e3b08aeSAndroid Build Coastguard Worker void Update(Id& id) { 108*9e3b08aeSAndroid Build Coastguard Worker const Id fid = Find(id); 109*9e3b08aeSAndroid Build Coastguard Worker // avoid silent stores 110*9e3b08aeSAndroid Build Coastguard Worker if (fid != id) { 111*9e3b08aeSAndroid Build Coastguard Worker id = fid; 112*9e3b08aeSAndroid Build Coastguard Worker } 113*9e3b08aeSAndroid Build Coastguard Worker } 114*9e3b08aeSAndroid Build Coastguard Worker 115*9e3b08aeSAndroid Build Coastguard Worker private: 116*9e3b08aeSAndroid Build Coastguard Worker Graph& graph_; 117*9e3b08aeSAndroid Build Coastguard Worker Id start_; 118*9e3b08aeSAndroid Build Coastguard Worker DenseIdMapping mapping_; 119*9e3b08aeSAndroid Build Coastguard Worker Runtime& runtime_; 120*9e3b08aeSAndroid Build Coastguard Worker Counter find_query_; 121*9e3b08aeSAndroid Build Coastguard Worker Counter find_halved_; 122*9e3b08aeSAndroid Build Coastguard Worker Counter union_known_; 123*9e3b08aeSAndroid Build Coastguard Worker Counter union_unknown_; 124*9e3b08aeSAndroid Build Coastguard Worker }; 125*9e3b08aeSAndroid Build Coastguard Worker 126*9e3b08aeSAndroid Build Coastguard Worker } // namespace stg 127*9e3b08aeSAndroid Build Coastguard Worker 128*9e3b08aeSAndroid Build Coastguard Worker #endif // STG_UNIFICATION_H_ 129