2018-08-14 18:44:28 +02:00
|
|
|
//===- CFGDiff.h - Define a CFG snapshot. -----------------------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// 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
|
2018-08-14 18:44:28 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file defines specializations of GraphTraits that allows generic
|
|
|
|
// algorithms to see a different snapshot of a CFG.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2020-04-10 09:14:10 +02:00
|
|
|
#ifndef LLVM_SUPPORT_CFGDIFF_H
|
|
|
|
#define LLVM_SUPPORT_CFGDIFF_H
|
2018-08-14 18:44:28 +02:00
|
|
|
|
|
|
|
#include "llvm/ADT/GraphTraits.h"
|
|
|
|
#include "llvm/ADT/iterator.h"
|
|
|
|
#include "llvm/ADT/iterator_range.h"
|
|
|
|
#include "llvm/Support/CFGUpdate.h"
|
|
|
|
#include "llvm/Support/type_traits.h"
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <iterator>
|
|
|
|
|
|
|
|
// Two booleans are used to define orders in graphs:
|
|
|
|
// InverseGraph defines when we need to reverse the whole graph and is as such
|
|
|
|
// also equivalent to applying updates in reverse.
|
|
|
|
// InverseEdge defines whether we want to change the edges direction. E.g., for
|
|
|
|
// a non-inversed graph, the children are naturally the successors when
|
|
|
|
// InverseEdge is false and the predecessors when InverseEdge is true.
|
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
2020-04-10 03:29:40 +02:00
|
|
|
namespace detail {
|
|
|
|
template <typename Range>
|
|
|
|
auto reverse_if_helper(Range &&R, std::integral_constant<bool, false>) {
|
|
|
|
return std::forward<Range>(R);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Range>
|
|
|
|
auto reverse_if_helper(Range &&R, std::integral_constant<bool, true>) {
|
|
|
|
return llvm::reverse(std::forward<Range>(R));
|
|
|
|
}
|
|
|
|
|
|
|
|
template <bool B, typename Range> auto reverse_if(Range &&R) {
|
|
|
|
return reverse_if_helper(std::forward<Range>(R),
|
|
|
|
std::integral_constant<bool, B>{});
|
|
|
|
}
|
|
|
|
} // namespace detail
|
|
|
|
|
2020-07-17 00:46:54 +02:00
|
|
|
// GraphDiff defines a CFG snapshot: given a set of Update<NodePtr>, provides
|
|
|
|
// a getChildren method to get a Node's children based on the additional updates
|
|
|
|
// in the snapshot. The current diff treats the CFG as a graph rather than a
|
2018-08-14 18:44:28 +02:00
|
|
|
// multigraph. Added edges are pruned to be unique, and deleted edges will
|
|
|
|
// remove all existing edges between two blocks.
|
[GraphDiff] Make InverseGraph a property of a GraphDiff.
Summary:
Treating a graph in reverse is a property of the GraphDiff and should instead be a template argument, just like IsPostDom is one for DomTrees.
If it's just an argument to all methods, we could have mismatches between the constructor of the GraphDiff which may reverse the updates when filtering them, and the calls retrieving the filtered delete/insert updates.
Also, since this will be used in IDF, where we're using a DomTree, this creates a cleaner interface for the GraphTraits to use the existing template argument of DomTreeBase.
Separate patch from the one adding GraphDiff, so get a clear diff of what changed.
Reviewers: timshen, kuhar
Subscribers: sanjoy, llvm-commits, jlebar
Differential Revision: https://reviews.llvm.org/D50687
llvm-svn: 339699
2018-08-14 19:43:24 +02:00
|
|
|
template <typename NodePtr, bool InverseGraph = false> class GraphDiff {
|
2020-07-25 01:29:58 +02:00
|
|
|
struct DeletesInserts {
|
|
|
|
SmallVector<NodePtr, 2> DI[2];
|
2020-03-27 23:02:23 +01:00
|
|
|
};
|
2020-07-25 01:29:58 +02:00
|
|
|
using UpdateMapType = SmallDenseMap<NodePtr, DeletesInserts>;
|
|
|
|
UpdateMapType Succ;
|
|
|
|
UpdateMapType Pred;
|
|
|
|
|
2020-03-27 23:02:23 +01:00
|
|
|
// By default, it is assumed that, given a CFG and a set of updates, we wish
|
|
|
|
// to apply these updates as given. If UpdatedAreReverseApplied is set, the
|
|
|
|
// updates will be applied in reverse: deleted edges are considered re-added
|
|
|
|
// and inserted edges are considered deleted when returning children.
|
|
|
|
bool UpdatedAreReverseApplied;
|
|
|
|
|
|
|
|
// Keep the list of legalized updates for a deterministic order of updates
|
|
|
|
// when using a GraphDiff for incremental updates in the DominatorTree.
|
|
|
|
// The list is kept in reverse to allow popping from end.
|
|
|
|
SmallVector<cfg::Update<NodePtr>, 4> LegalizedUpdates;
|
2018-08-14 18:44:28 +02:00
|
|
|
|
|
|
|
void printMap(raw_ostream &OS, const UpdateMapType &M) const {
|
2020-07-25 01:29:58 +02:00
|
|
|
StringRef DIText[2] = {"Delete", "Insert"};
|
|
|
|
for (auto Pair : M) {
|
|
|
|
for (unsigned IsInsert = 0; IsInsert <= 1; ++IsInsert) {
|
|
|
|
OS << DIText[IsInsert] << " edges: \n";
|
|
|
|
for (auto Child : Pair.second.DI[IsInsert]) {
|
|
|
|
OS << "(";
|
|
|
|
Pair.first->printAsOperand(OS, false);
|
|
|
|
OS << ", ";
|
|
|
|
Child->printAsOperand(OS, false);
|
|
|
|
OS << ") ";
|
|
|
|
}
|
2018-08-14 18:44:28 +02:00
|
|
|
}
|
2020-07-25 01:29:58 +02:00
|
|
|
}
|
2018-08-14 18:44:28 +02:00
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2020-03-27 23:02:23 +01:00
|
|
|
GraphDiff() : UpdatedAreReverseApplied(false) {}
|
|
|
|
GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates,
|
|
|
|
bool ReverseApplyUpdates = false) {
|
2020-04-10 03:29:40 +02:00
|
|
|
cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph);
|
2018-08-14 18:44:28 +02:00
|
|
|
for (auto U : LegalizedUpdates) {
|
2020-03-27 23:02:23 +01:00
|
|
|
unsigned IsInsert =
|
|
|
|
(U.getKind() == cfg::UpdateKind::Insert) == !ReverseApplyUpdates;
|
2020-07-25 01:29:58 +02:00
|
|
|
Succ[U.getFrom()].DI[IsInsert].push_back(U.getTo());
|
|
|
|
Pred[U.getTo()].DI[IsInsert].push_back(U.getFrom());
|
2018-08-14 18:44:28 +02:00
|
|
|
}
|
2020-03-27 23:02:23 +01:00
|
|
|
UpdatedAreReverseApplied = ReverseApplyUpdates;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto getLegalizedUpdates() const {
|
|
|
|
return make_range(LegalizedUpdates.begin(), LegalizedUpdates.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned getNumLegalizedUpdates() const { return LegalizedUpdates.size(); }
|
|
|
|
|
|
|
|
cfg::Update<NodePtr> popUpdateForIncrementalUpdates() {
|
|
|
|
assert(!LegalizedUpdates.empty() && "No updates to apply!");
|
|
|
|
auto U = LegalizedUpdates.pop_back_val();
|
|
|
|
unsigned IsInsert =
|
|
|
|
(U.getKind() == cfg::UpdateKind::Insert) == !UpdatedAreReverseApplied;
|
2020-07-25 01:29:58 +02:00
|
|
|
auto &SuccDIList = Succ[U.getFrom()];
|
|
|
|
auto &SuccList = SuccDIList.DI[IsInsert];
|
2020-03-27 23:02:23 +01:00
|
|
|
assert(SuccList.back() == U.getTo());
|
|
|
|
SuccList.pop_back();
|
2020-07-25 01:29:58 +02:00
|
|
|
if (SuccList.empty() && SuccDIList.DI[!IsInsert].empty())
|
|
|
|
Succ.erase(U.getFrom());
|
2020-03-27 23:02:23 +01:00
|
|
|
|
2020-07-25 01:29:58 +02:00
|
|
|
auto &PredDIList = Pred[U.getTo()];
|
|
|
|
auto &PredList = PredDIList.DI[IsInsert];
|
2020-03-27 23:02:23 +01:00
|
|
|
assert(PredList.back() == U.getFrom());
|
|
|
|
PredList.pop_back();
|
2020-07-25 01:29:58 +02:00
|
|
|
if (PredList.empty() && PredDIList.DI[!IsInsert].empty())
|
|
|
|
Pred.erase(U.getTo());
|
2020-03-27 23:02:23 +01:00
|
|
|
return U;
|
2018-08-14 18:44:28 +02:00
|
|
|
}
|
|
|
|
|
2020-04-10 03:29:40 +02:00
|
|
|
using VectRet = SmallVector<NodePtr, 8>;
|
|
|
|
template <bool InverseEdge> VectRet getChildren(NodePtr N) const {
|
|
|
|
using DirectedNodeT =
|
|
|
|
std::conditional_t<InverseEdge, Inverse<NodePtr>, NodePtr>;
|
|
|
|
auto R = children<DirectedNodeT>(N);
|
2020-07-25 01:29:58 +02:00
|
|
|
VectRet Res = VectRet(detail::reverse_if<!InverseEdge>(R));
|
|
|
|
|
|
|
|
// Remove nullptr children for clang.
|
|
|
|
llvm::erase_value(Res, nullptr);
|
|
|
|
|
|
|
|
auto &Children = (InverseEdge != InverseGraph) ? Pred : Succ;
|
|
|
|
auto It = Children.find(N);
|
|
|
|
if (It == Children.end())
|
|
|
|
return Res;
|
|
|
|
|
|
|
|
// Remove children present in the CFG but not in the snapshot.
|
|
|
|
for (auto *Child : It->second.DI[0])
|
|
|
|
llvm::erase_value(Res, Child);
|
2020-04-10 03:29:40 +02:00
|
|
|
|
2020-07-25 01:29:58 +02:00
|
|
|
// Add children present in the snapshot for not in the real CFG.
|
|
|
|
auto &AddedChildren = It->second.DI[1];
|
2021-01-07 03:27:33 +01:00
|
|
|
llvm::append_range(Res, AddedChildren);
|
2020-04-10 03:29:40 +02:00
|
|
|
|
2020-07-25 01:29:58 +02:00
|
|
|
return Res;
|
2020-04-10 03:29:40 +02:00
|
|
|
}
|
|
|
|
|
2018-08-14 18:44:28 +02:00
|
|
|
void print(raw_ostream &OS) const {
|
|
|
|
OS << "===== GraphDiff: CFG edge changes to create a CFG snapshot. \n"
|
|
|
|
"===== (Note: notion of children/inverse_children depends on "
|
|
|
|
"the direction of edges and the graph.)\n";
|
2020-07-25 01:29:58 +02:00
|
|
|
OS << "Children to delete/insert:\n\t";
|
|
|
|
printMap(OS, Succ);
|
|
|
|
OS << "Inverse_children to delete/insert:\n\t";
|
|
|
|
printMap(OS, Pred);
|
2018-08-14 18:44:28 +02:00
|
|
|
OS << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
|
|
|
|
#endif
|
|
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
|
2020-04-10 09:14:10 +02:00
|
|
|
#endif // LLVM_SUPPORT_CFGDIFF_H
|