//===- CFGUpdate.h - Encode a CFG Edge Update. ------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file defines a CFG Edge Update: Insert or Delete, and two Nodes as the // Edge ends. // //===----------------------------------------------------------------------===// #ifndef LLVM_SUPPORT_CFGUPDATE_H #define LLVM_SUPPORT_CFGUPDATE_H #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" namespace llvm { namespace cfg { enum class UpdateKind : unsigned char { Insert, Delete }; template class Update { using NodeKindPair = PointerIntPair; NodePtr From; NodeKindPair ToAndKind; public: Update(UpdateKind Kind, NodePtr From, NodePtr To) : From(From), ToAndKind(To, Kind) {} UpdateKind getKind() const { return ToAndKind.getInt(); } NodePtr getFrom() const { return From; } NodePtr getTo() const { return ToAndKind.getPointer(); } bool operator==(const Update &RHS) const { return From == RHS.From && ToAndKind == RHS.ToAndKind; } void print(raw_ostream &OS) const { OS << (getKind() == UpdateKind::Insert ? "Insert " : "Delete "); getFrom()->printAsOperand(OS, false); OS << " -> "; getTo()->printAsOperand(OS, false); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void dump() const { print(dbgs()); } #endif }; // LegalizeUpdates function simplifies updates assuming a graph structure. // This function serves double purpose: // a) It removes redundant updates, which makes it easier to reverse-apply // them when traversing CFG. // b) It optimizes away updates that cancel each other out, as the end result // is the same. template void LegalizeUpdates(ArrayRef> AllUpdates, SmallVectorImpl> &Result, bool InverseGraph, bool ReverseResultOrder = false) { // Count the total number of inserions of each edge. // Each insertion adds 1 and deletion subtracts 1. The end number should be // one of {-1 (deletion), 0 (NOP), +1 (insertion)}. Otherwise, the sequence // of updates contains multiple updates of the same kind and we assert for // that case. SmallDenseMap, int, 4> Operations; Operations.reserve(AllUpdates.size()); for (const auto &U : AllUpdates) { NodePtr From = U.getFrom(); NodePtr To = U.getTo(); if (InverseGraph) std::swap(From, To); // Reverse edge for postdominators. Operations[{From, To}] += (U.getKind() == UpdateKind::Insert ? 1 : -1); } Result.clear(); Result.reserve(Operations.size()); for (auto &Op : Operations) { const int NumInsertions = Op.second; assert(std::abs(NumInsertions) <= 1 && "Unbalanced operations!"); if (NumInsertions == 0) continue; const UpdateKind UK = NumInsertions > 0 ? UpdateKind::Insert : UpdateKind::Delete; Result.push_back({UK, Op.first.first, Op.first.second}); } // Make the order consistent by not relying on pointer values within the // set. Reuse the old Operations map. // In the future, we should sort by something else to minimize the amount // of work needed to perform the series of updates. for (size_t i = 0, e = AllUpdates.size(); i != e; ++i) { const auto &U = AllUpdates[i]; if (!InverseGraph) Operations[{U.getFrom(), U.getTo()}] = int(i); else Operations[{U.getTo(), U.getFrom()}] = int(i); } llvm::sort(Result, [&](const Update &A, const Update &B) { const auto &OpA = Operations[{A.getFrom(), A.getTo()}]; const auto &OpB = Operations[{B.getFrom(), B.getTo()}]; return ReverseResultOrder ? OpA < OpB : OpA > OpB; }); } } // end namespace cfg } // end namespace llvm #endif // LLVM_SUPPORT_CFGUPDATE_H