#ifndef LLVM_SUPPORT_CFGDIFF_H
#define LLVM_SUPPORT_CFGDIFF_H
#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>
namespace llvm {
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>{});
}
}
template <typename NodePtr, bool InverseGraph = false> class GraphDiff {
struct DeletesInserts {
SmallVector<NodePtr, 2> DI[2];
};
using UpdateMapType = SmallDenseMap<NodePtr, DeletesInserts>;
UpdateMapType Succ;
UpdateMapType Pred;
bool UpdatedAreReverseApplied;
SmallVector<cfg::Update<NodePtr>, 4> LegalizedUpdates;
void printMap(raw_ostream &OS, const UpdateMapType &M) const {
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 << ") ";
}
}
}
OS << "\n";
}
public:
GraphDiff() : UpdatedAreReverseApplied(false) {}
GraphDiff(ArrayRef<cfg::Update<NodePtr>> Updates,
bool ReverseApplyUpdates = false) {
cfg::LegalizeUpdates<NodePtr>(Updates, LegalizedUpdates, InverseGraph);
for (auto U : LegalizedUpdates) {
unsigned IsInsert =
(U.getKind() == cfg::UpdateKind::Insert) == !ReverseApplyUpdates;
Succ[U.getFrom()].DI[IsInsert].push_back(U.getTo());
Pred[U.getTo()].DI[IsInsert].push_back(U.getFrom());
}
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;
auto &SuccDIList = Succ[U.getFrom()];
auto &SuccList = SuccDIList.DI[IsInsert];
assert(SuccList.back() == U.getTo());
SuccList.pop_back();
if (SuccList.empty() && SuccDIList.DI[!IsInsert].empty())
Succ.erase(U.getFrom());
auto &PredDIList = Pred[U.getTo()];
auto &PredList = PredDIList.DI[IsInsert];
assert(PredList.back() == U.getFrom());
PredList.pop_back();
if (PredList.empty() && PredDIList.DI[!IsInsert].empty())
Pred.erase(U.getTo());
return U;
}
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);
VectRet Res = VectRet(detail::reverse_if<!InverseEdge>(R));
llvm::erase_value(Res, nullptr);
auto &Children = (InverseEdge != InverseGraph) ? Pred : Succ;
auto It = Children.find(N);
if (It == Children.end())
return Res;
for (auto *Child : It->second.DI[0])
llvm::erase_value(Res, Child);
auto &AddedChildren = It->second.DI[1];
llvm::append_range(Res, AddedChildren);
return Res;
}
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";
OS << "Children to delete/insert:\n\t";
printMap(OS, Succ);
OS << "Inverse_children to delete/insert:\n\t";
printMap(OS, Pred);
OS << "\n";
}
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void dump() const { print(dbgs()); }
#endif
};
}
#endif