nhaehnle updated this revision to Diff 287441.
nhaehnle added a comment.

- cleanup operators on CfgOpaqueType
- address other review comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D83088/new/

https://reviews.llvm.org/D83088

Files:
  clang/include/clang/Analysis/Analyses/Dominators.h
  llvm/include/llvm/CodeGen/MachineCfgTraits.h
  llvm/include/llvm/IR/CFG.h
  llvm/include/llvm/Support/CfgTraits.h
  llvm/lib/CodeGen/CMakeLists.txt
  llvm/lib/CodeGen/MachineCfgTraits.cpp
  llvm/lib/IR/CFG.cpp
  llvm/lib/IR/CMakeLists.txt
  llvm/lib/Support/CMakeLists.txt
  llvm/lib/Support/CfgTraits.cpp
  llvm/lib/Transforms/Vectorize/VPlanDominatorTree.h
  mlir/include/mlir/IR/Dominance.h

Index: mlir/include/mlir/IR/Dominance.h
===================================================================
--- mlir/include/mlir/IR/Dominance.h
+++ mlir/include/mlir/IR/Dominance.h
@@ -10,8 +10,46 @@
 #define MLIR_IR_DOMINANCE_H
 
 #include "mlir/IR/RegionGraphTraits.h"
+#include "llvm/Support/CfgTraits.h"
 #include "llvm/Support/GenericDomTree.h"
 
+namespace mlir {
+
+/// Partial CFG traits for MLIR's CFG, without a value type.
+class CfgTraitsBase : public llvm::CfgTraitsBase {
+public:
+  using ParentType = Region;
+  using BlockRef = Block *;
+  using ValueRef = void;
+
+  static llvm::CfgBlockRef wrapRef(BlockRef block) {
+    return makeOpaque<llvm::CfgBlockRefTag>(block);
+  }
+  static BlockRef unwrapRef(llvm::CfgBlockRef block) {
+    return static_cast<BlockRef>(getOpaque(block));
+  }
+};
+
+class CfgTraits : public llvm::CfgTraits<CfgTraitsBase, CfgTraits> {
+public:
+  static Region *getBlockParent(Block *block) { return block->getParent(); }
+
+  static auto predecessors(Block *block) {
+    return llvm::inverse_children<Block *>(block);
+  }
+
+  static auto successors(Block *block) {
+    return llvm::children<Block *>(block);
+  }
+};
+
+} // namespace mlir
+
+template <>
+struct llvm::CfgTraitsFor<mlir::Block> {
+  using CfgTraits = mlir::CfgTraits;
+};
+
 extern template class llvm::DominatorTreeBase<mlir::Block, false>;
 extern template class llvm::DominatorTreeBase<mlir::Block, true>;
 
Index: llvm/lib/Transforms/Vectorize/VPlanDominatorTree.h
===================================================================
--- llvm/lib/Transforms/Vectorize/VPlanDominatorTree.h
+++ llvm/lib/Transforms/Vectorize/VPlanDominatorTree.h
@@ -18,9 +18,42 @@
 #include "VPlan.h"
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/IR/Dominators.h"
+#include "llvm/Support/CfgTraits.h"
 
 namespace llvm {
 
+/// Partial CFG traits for VPlan's CFG, without a value type.
+class VPCfgTraitsBase : public CfgTraitsBase {
+public:
+  using ParentType = VPRegionBlock;
+  using BlockRef = VPBlockBase *;
+  using ValueRef = void;
+
+  static CfgBlockRef wrapRef(BlockRef block) {
+    return makeOpaque<CfgBlockRefTag>(block);
+  }
+  static BlockRef unwrapRef(CfgBlockRef block) {
+    return static_cast<BlockRef>(getOpaque(block));
+  }
+};
+
+class VPCfgTraits : public CfgTraits<VPCfgTraitsBase, VPCfgTraits> {
+public:
+  static VPRegionBlock *getBlockParent(VPBlockBase *block) {
+    return block->getParent();
+  }
+
+  static auto predecessors(VPBlockBase *block) {
+    return llvm::inverse_children<VPBlockBase *>(block);
+  }
+
+  static auto successors(VPBlockBase *block) {
+    return llvm::children<VPBlockBase *>(block);
+  }
+};
+
+template <> struct CfgTraitsFor<VPBlockBase> { using CfgTraits = VPCfgTraits; };
+
 /// Template specialization of the standard LLVM dominator tree utility for
 /// VPBlockBases.
 using VPDominatorTree = DomTreeBase<VPBlockBase>;
Index: llvm/lib/Support/CfgTraits.cpp
===================================================================
--- /dev/null
+++ llvm/lib/Support/CfgTraits.cpp
@@ -0,0 +1,14 @@
+//===- CfgTraits.cpp - Traits for generically working on CFGs ---*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/CfgTraits.h"
+
+using namespace llvm;
+
+void CfgInterface::anchor() {}
+void CfgPrinter::anchor() {}
Index: llvm/lib/Support/CMakeLists.txt
===================================================================
--- llvm/lib/Support/CMakeLists.txt
+++ llvm/lib/Support/CMakeLists.txt
@@ -83,6 +83,7 @@
   BranchProbability.cpp
   BuryPointer.cpp
   CachePruning.cpp
+  CfgTraits.cpp
   circular_raw_ostream.cpp
   Chrono.cpp
   COM.cpp
Index: llvm/lib/IR/CMakeLists.txt
===================================================================
--- llvm/lib/IR/CMakeLists.txt
+++ llvm/lib/IR/CMakeLists.txt
@@ -4,6 +4,7 @@
   Attributes.cpp
   AutoUpgrade.cpp
   BasicBlock.cpp
+  CFG.cpp
   Comdat.cpp
   ConstantFold.cpp
   ConstantRange.cpp
Index: llvm/lib/IR/CFG.cpp
===================================================================
--- /dev/null
+++ llvm/lib/IR/CFG.cpp
@@ -0,0 +1,56 @@
+//===- CFG.cpp --------------------------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/CFG.h"
+
+#include "llvm/IR/ModuleSlotTracker.h"
+
+using namespace llvm;
+
+IrCfgTraits::Printer::Printer(const IrCfgTraits &) {}
+IrCfgTraits::Printer::~Printer() {}
+
+void IrCfgTraits::Printer::printValue(raw_ostream &out, ValueRef value) const {
+  if (!m_moduleSlotTracker) {
+    const Function *function = nullptr;
+
+    if (auto *instruction = dyn_cast<Instruction>(value)) {
+      function = instruction->getParent()->getParent();
+    } else if (auto *argument = dyn_cast<Argument>(value)) {
+      function = argument->getParent();
+    }
+
+    if (function)
+      ensureModuleSlotTracker(*function);
+  }
+
+  if (m_moduleSlotTracker) {
+    value->print(out, *m_moduleSlotTracker, true);
+  } else {
+    value->print(out, true);
+  }
+}
+
+void IrCfgTraits::Printer::printBlockName(raw_ostream &out,
+                                          BlockRef block) const {
+  if (block->hasName()) {
+    out << block->getName();
+  } else {
+    ensureModuleSlotTracker(*block->getParent());
+    out << m_moduleSlotTracker->getLocalSlot(block);
+  }
+}
+
+void IrCfgTraits::Printer::ensureModuleSlotTracker(
+    const Function &function) const {
+  if (!m_moduleSlotTracker) {
+    m_moduleSlotTracker =
+        std::make_unique<ModuleSlotTracker>(function.getParent(), false);
+    m_moduleSlotTracker->incorporateFunction(function);
+  }
+}
Index: llvm/lib/CodeGen/MachineCfgTraits.cpp
===================================================================
--- /dev/null
+++ llvm/lib/CodeGen/MachineCfgTraits.cpp
@@ -0,0 +1,30 @@
+//===- MachineCycleInfo.cpp - Cycle Info for Machine IR ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/CodeGen/MachineCfgTraits.h"
+
+#include "llvm/IR/BasicBlock.h"
+
+using namespace llvm;
+
+void MachineCfgTraits::Printer::printValue(raw_ostream &out,
+                                           Register value) const {
+  out << printReg(value, m_regInfo->getTargetRegisterInfo(), 0, m_regInfo);
+
+  if (value) {
+    out << ": ";
+
+    MachineInstr *instr = m_regInfo->getUniqueVRegDef(value);
+    instr->print(out);
+  }
+}
+
+void MachineCfgTraits::Printer::printBlockName(raw_ostream &out,
+                                               MachineBasicBlock *block) const {
+  block->printName(out);
+}
Index: llvm/lib/CodeGen/CMakeLists.txt
===================================================================
--- llvm/lib/CodeGen/CMakeLists.txt
+++ llvm/lib/CodeGen/CMakeLists.txt
@@ -72,6 +72,7 @@
   MachineBlockFrequencyInfo.cpp
   MachineBlockPlacement.cpp
   MachineBranchProbabilityInfo.cpp
+  MachineCfgTraits.cpp
   MachineCombiner.cpp
   MachineCopyPropagation.cpp
   MachineCSE.cpp
Index: llvm/include/llvm/Support/CfgTraits.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/Support/CfgTraits.h
@@ -0,0 +1,474 @@
+//===- CfgTraits.h - Traits for generically working on CFGs -----*- 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines a traits template \ref CfgTraits as well as the
+/// \ref CfgInterface abstract interface and \ref CfgInterfaceImpl that help
+/// in writing algorithms that are generic over CFGs, e.g. operating on both
+/// LLVM IR and MachineIR.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_CFGTRAITS_H
+#define LLVM_SUPPORT_CFGTRAITS_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMapInfo.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/Support/Printable.h"
+
+namespace llvm {
+
+template <typename Tag> class CfgOpaqueType;
+
+template <typename Tag>
+bool operator==(CfgOpaqueType<Tag> lhs, CfgOpaqueType<Tag> rhs);
+template <typename Tag>
+bool operator<(CfgOpaqueType<Tag> lhs, CfgOpaqueType<Tag> rhs);
+
+/// \brief Type-erased references to CFG objects (blocks, values).
+///
+/// Use CfgTraits::{wrapRef, unwrapRef} to wrap and unwrap concrete object
+/// references.
+///
+/// The most common use is to hold a pointer, but arbitrary uintptr_t values
+/// may be stored by CFGs. Note that 0, -1, and -2 have special interpretations:
+///  * 0 / nullptr: default-constructed value; evaluates to false in boolean
+///                 contexts.
+///  * -1: dense map empty marker
+///  * -2: dense map tombstone
+template <typename Tag> class CfgOpaqueType {
+  friend class CfgTraitsBase;
+  friend struct DenseMapInfo<CfgOpaqueType<Tag>>;
+  template <typename BaseTraits, typename FullTraits> friend class CfgTraits;
+  template <typename T>
+  friend bool operator==(CfgOpaqueType<T>, CfgOpaqueType<T>);
+  template <typename T>
+  friend bool operator<(CfgOpaqueType<T>, CfgOpaqueType<T>);
+
+  void *ptr = nullptr;
+
+  explicit CfgOpaqueType(void *ptr) : ptr(ptr) {}
+  void *get() const { return ptr; }
+
+public:
+  CfgOpaqueType() = default;
+
+  explicit operator bool() const { return ptr != nullptr; }
+};
+
+template <typename Tag>
+bool operator==(CfgOpaqueType<Tag> lhs, CfgOpaqueType<Tag> rhs) {
+  return lhs.get() == rhs.get();
+}
+
+template <typename Tag>
+bool operator!=(CfgOpaqueType<Tag> lhs, CfgOpaqueType<Tag> rhs) {
+  return !(lhs == rhs);
+}
+
+template <typename Tag>
+bool operator<(CfgOpaqueType<Tag> lhs, CfgOpaqueType<Tag> rhs) {
+  return lhs.get() < rhs.get();
+}
+
+template <typename Tag> struct DenseMapInfo<CfgOpaqueType<Tag>> {
+  using Type = CfgOpaqueType<Tag>;
+
+  static Type getEmptyKey() {
+    uintptr_t val = static_cast<uintptr_t>(-1);
+    return Type(reinterpret_cast<void *>(val));
+  }
+
+  static Type getTombstoneKey() {
+    uintptr_t val = static_cast<uintptr_t>(-2);
+    return Type(reinterpret_cast<void *>(val));
+  }
+
+  static unsigned getHashValue(Type val) {
+    return llvm::DenseMapInfo<void *>::getHashValue(val.get());
+  }
+  static bool isEqual(Type lhs, Type rhs) { return lhs == rhs; }
+};
+
+class CfgParentRefTag;
+using CfgParentRef = CfgOpaqueType<CfgParentRefTag>;
+
+class CfgBlockRefTag;
+using CfgBlockRef = CfgOpaqueType<CfgBlockRefTag>;
+
+class CfgValueRefTag;
+using CfgValueRef = CfgOpaqueType<CfgValueRefTag>;
+
+/// \brief Base class for CFG traits
+///
+/// Derive from this base class to define the mapping between opaque types and
+/// concrete CFG types. Then derive from \ref CfgTraits to implement
+/// operations such as traversal of the CFG.
+class CfgTraitsBase {
+protected:
+  template <typename Tag> static auto makeOpaque(void *ptr) {
+    CfgOpaqueType<Tag> ref;
+    ref.ptr = ptr;
+    return ref;
+  }
+
+  template <typename Tag> static void *getOpaque(CfgOpaqueType<Tag> opaque) {
+    return opaque.ptr;
+  }
+
+public:
+  // To be implemented by derived classes:
+  //
+  // - The type of the "parent" of the CFG, e.g. `llvm::Function`
+  //   using ParentType = ...;
+  //
+  // - The type of block references in the CFG, e.g. `llvm::BasicBlock *`
+  //   using BlockRef = ...;
+  //
+  // - The type of value references in the CFG, e.g. `llvm::Value *`
+  //   using ValueRef = ...;
+  //
+  // - Static methods for converting BlockRef and ValueRef to and from
+  //   static CfgBlockRef wrapRef(BlockRef);
+  //   static CfgValueRef wrapRef(ValueRef);
+  //   static BlockRef unwrapRef(CfgBlockRef);
+  //   static ValueRef unwrapRef(CfgValueRef);
+};
+
+/// \brief CFG traits
+///
+/// Implement CFG traits by:
+///  - Deriving from CfgTraitsBase to designate block and value types and
+///    implementing wrapRef / unwrapRef
+///  - Deriving from CfgTraits using CRTP and implement / override additional
+///    methods for CFG traversal, printing, etc.
+///
+/// This somewhat surprising two-step helps with the implementation of
+/// (un)wrapping_iterators.
+///
+template <typename BaseTraits, typename FullTraits>
+class CfgTraits : public BaseTraits {
+public:
+  using typename BaseTraits::BlockRef;
+  using typename BaseTraits::ParentType;
+  using typename BaseTraits::ValueRef;
+
+  /// Functionality to be provided by implementations:
+  ///@{
+
+  // Constructor: initialize from a pointer to the parent.
+  //   explicit CfgTraits(ParentType *parent);
+
+  // Find the parent for a given block.
+  //   static ParentType *getBlockParent(BlockRef block);
+
+  // Iterate over blocks in the CFG containing the given block in an arbitrary
+  // order (start with entry block, return a range of iterators dereferencing
+  // to BlockRef):
+  //   static auto blocks(ParentType *parent);
+
+  // Iterate over the predecessors / successors of a block (return a range
+  // of iterators dereferencing to BlockRef):
+  //   static auto predecessors(BlockRef block);
+  //   static auto successors(BlockRef block);
+
+  // Iterate over the values defined in a basic block in program order (return
+  // a range of iterators dereferencing to ValueRef):
+  //   static auto blockdefs(BlockRef block);
+
+  // Get the block in which a given value is defined. Returns a null-like
+  // BlockRef if the value is not defined in a block (e.g. it is a constant or
+  // function argument).
+  //   BlockRef getValueDefBlock(ValueRef value) const;
+
+  // struct Printer {
+  //   explicit Printer(const CfgTraits &traits);
+  //   void printBlockName(raw_ostream &out, BlockRef block) const;
+  //   void printValue(raw_ostream &out, ValueRef value) const;
+  // };
+
+  ///@}
+
+  static CfgParentRef wrapRef(ParentType *parent) {
+    return CfgParentRef{parent};
+  }
+
+  static ParentType *unwrapRef(CfgParentRef parent) {
+    return static_cast<ParentType *>(parent.get());
+  }
+
+  using BaseTraits::unwrapRef;
+  using BaseTraits::wrapRef;
+
+  template <typename BaseIteratorT> struct unwrapping_iterator;
+
+  template <typename BaseIteratorT>
+  using unwrapping_iterator_base = iterator_adaptor_base<
+      unwrapping_iterator<BaseIteratorT>, BaseIteratorT,
+      typename std::iterator_traits<BaseIteratorT>::iterator_category,
+      // value_type
+      decltype(BaseTraits::unwrapRef(*std::declval<BaseIteratorT>())),
+      typename std::iterator_traits<BaseIteratorT>::difference_type,
+      // pointer (not really usable, but we need to put something here)
+      decltype(BaseTraits::unwrapRef(*std::declval<BaseIteratorT>())) *,
+      // reference (not a true reference, because operator* doesn't return one)
+      decltype(BaseTraits::unwrapRef(*std::declval<BaseIteratorT>()))>;
+
+  template <typename BaseIteratorT>
+  struct unwrapping_iterator : unwrapping_iterator_base<BaseIteratorT> {
+    using Base = unwrapping_iterator_base<BaseIteratorT>;
+
+    unwrapping_iterator() = default;
+    explicit unwrapping_iterator(BaseIteratorT &&it)
+        : Base(std::forward<BaseIteratorT>(it)) {}
+
+    auto operator*() const { return BaseTraits::unwrapRef(*this->I); }
+  };
+
+  template <typename BaseIteratorT> struct wrapping_iterator;
+
+  template <typename BaseIteratorT>
+  using wrapping_iterator_base = iterator_adaptor_base<
+      wrapping_iterator<BaseIteratorT>, BaseIteratorT,
+      typename std::iterator_traits<BaseIteratorT>::iterator_category,
+      // value_type
+      decltype(BaseTraits::wrapRef(*std::declval<BaseIteratorT>())),
+      typename std::iterator_traits<BaseIteratorT>::difference_type,
+      // pointer (not really usable, but we need to put something here)
+      decltype(BaseTraits::wrapRef(*std::declval<BaseIteratorT>())) *,
+      // reference (not a true reference, because operator* doesn't return one)
+      decltype(BaseTraits::wrapRef(*std::declval<BaseIteratorT>()))>;
+
+  template <typename BaseIteratorT>
+  struct wrapping_iterator : wrapping_iterator_base<BaseIteratorT> {
+    using Base = wrapping_iterator_base<BaseIteratorT>;
+
+    wrapping_iterator() = default;
+    explicit wrapping_iterator(BaseIteratorT &&it)
+        : Base(std::forward<BaseIteratorT>(it)) {}
+
+    auto operator*() const { return BaseTraits::wrapRef(*this->I); }
+  };
+
+  /// Convert an iterator of CfgBlockRef or CfgValueRef into an iterator of
+  /// BlockRef or ValueRef.
+  template <typename IteratorT> static auto unwrapIterator(IteratorT &&it) {
+    return unwrapping_iterator<IteratorT>(std::forward<IteratorT>(it));
+  }
+
+  /// Convert a range of CfgBlockRef or CfgValueRef into a range of
+  /// BlockRef or ValueRef.
+  template <typename RangeT> static auto unwrapRange(RangeT &&range) {
+    return llvm::make_range(
+        unwrapIterator(adl_begin(std::forward<RangeT>(range))),
+        unwrapIterator(adl_end(std::forward<RangeT>(range))));
+  }
+
+  /// Convert an iterator of BlockRef or ValueRef into an iterator of
+  /// CfgBlockRef or CfgValueRef.
+  template <typename IteratorT> static auto wrapIterator(IteratorT &&it) {
+    return wrapping_iterator<IteratorT>(std::forward<IteratorT>(it));
+  }
+
+  /// Convert a range of BlockRef or ValueRef into a range of CfgBlockRef or
+  /// CfgValueRef.
+  template <typename RangeT> static auto wrapRange(RangeT &&range) {
+    return llvm::make_range(
+        wrapIterator(adl_begin(std::forward<RangeT>(range))),
+        wrapIterator(adl_end(std::forward<RangeT>(range))));
+  }
+};
+
+/// \brief Obtain CfgTraits given the basic block type.
+///
+/// This template is provided to ease the transition to the use of CfgTraits.
+/// Existing templates e.g. over the basic block type can use this to derive
+/// the appropriate CfgTraits implementation via
+/// typename CfgTraitsFor<BlockT>::CfgTraits.
+template <typename CfgRelatedTypeT> struct CfgTraitsFor;
+// Specializations need to include:
+//   using CfgTraits = ...;
+
+class CfgPrinter;
+
+/// \brief Type-erased "CFG traits"
+///
+/// Non-template algorithms that operate generically over CFG types can use this
+/// interface to query for CFG-specific functionality.
+///
+/// Note: This interface should only be implemented by \ref CfgInterfaceImpl.
+class CfgInterface {
+  virtual void anchor();
+
+public:
+  virtual ~CfgInterface() = default;
+
+  /// Escape-hatch for obtaining a printer e.g. in debug code. Prefer to
+  /// explicitly pass a CfgPrinter where possible.
+  virtual std::unique_ptr<CfgPrinter> makePrinter() const = 0;
+
+  virtual CfgParentRef getBlockParent(CfgBlockRef block) const = 0;
+
+  virtual void appendBlocks(CfgParentRef parent,
+                            SmallVectorImpl<CfgBlockRef> &list) const = 0;
+
+  virtual void appendPredecessors(CfgBlockRef block,
+                                  SmallVectorImpl<CfgBlockRef> &list) const = 0;
+  virtual void appendSuccessors(CfgBlockRef block,
+                                SmallVectorImpl<CfgBlockRef> &list) const = 0;
+  virtual ArrayRef<CfgBlockRef>
+  getPredecessors(CfgBlockRef block,
+                  SmallVectorImpl<CfgBlockRef> &store) const = 0;
+  virtual ArrayRef<CfgBlockRef>
+  getSuccessors(CfgBlockRef block,
+                SmallVectorImpl<CfgBlockRef> &store) const = 0;
+
+  virtual void appendBlockDefs(CfgBlockRef block,
+                               SmallVectorImpl<CfgValueRef> &list) const = 0;
+  virtual CfgBlockRef getValueDefBlock(CfgValueRef value) const = 0;
+};
+
+/// \brief Type-erased "CFG printer"
+///
+/// Separate from CfgInterface because some CFG printing requires tracking
+/// expensive data structures, and we'd like to avoid the cost of
+/// (conditionally) tearing them down in the common case.
+class CfgPrinter {
+  virtual void anchor();
+
+protected:
+  const CfgInterface &m_iface;
+
+  CfgPrinter(const CfgInterface &iface) : m_iface(iface) {}
+
+public:
+  virtual ~CfgPrinter() {}
+
+  const CfgInterface &interface() const { return m_iface; }
+
+  virtual void printBlockName(raw_ostream &out, CfgBlockRef block) const = 0;
+  virtual void printValue(raw_ostream &out, CfgValueRef value) const = 0;
+
+  Printable printableBlockName(CfgBlockRef block) const {
+    return Printable(
+        [this, block](raw_ostream &out) { printBlockName(out, block); });
+  }
+  Printable printableValue(CfgValueRef value) const {
+    return Printable(
+        [this, value](raw_ostream &out) { printValue(out, value); });
+  }
+};
+
+template <typename CfgTraitsT> class CfgPrinterImpl;
+
+/// \brief Implementation of type-erased "CFG traits"
+///
+/// Note: Do not specialize this template; adjust the CfgTraits type instead
+/// where necessary.
+template <typename CfgTraitsT>
+class CfgInterfaceImpl final : public CfgInterface,
+                               private CfgTraitsT { // empty base optimization
+public:
+  using CfgTraits = CfgTraitsT;
+  using BlockRef = typename CfgTraits::BlockRef;
+  using ValueRef = typename CfgTraits::ValueRef;
+  using ParentType = typename CfgTraits::ParentType;
+
+  friend CfgPrinterImpl<CfgTraits>;
+
+public:
+  explicit CfgInterfaceImpl(ParentType *parent) : CfgTraits(parent) {}
+
+  std::unique_ptr<CfgPrinter> makePrinter() const final {
+    return std::make_unique<CfgPrinterImpl<CfgTraits>>(*this);
+  }
+
+  CfgParentRef getBlockParent(CfgBlockRef block) const final {
+    return CfgTraits::wrapRef(
+        CfgTraits::getBlockParent(CfgTraits::unwrapRef(block)));
+  }
+
+  void appendBlocks(CfgParentRef parent,
+                    SmallVectorImpl<CfgBlockRef> &list) const final {
+    auto range = CfgTraits::blocks(CfgTraits::unwrapRef(parent));
+    list.insert(list.end(), CfgTraits::wrapIterator(std::begin(range)),
+                CfgTraits::wrapIterator(std::end(range)));
+  }
+
+  void appendPredecessors(CfgBlockRef block,
+                          SmallVectorImpl<CfgBlockRef> &list) const final {
+    auto range = CfgTraits::predecessors(CfgTraits::unwrapRef(block));
+    list.insert(list.end(), CfgTraits::wrapIterator(std::begin(range)),
+                CfgTraits::wrapIterator(std::end(range)));
+  }
+  void appendSuccessors(CfgBlockRef block,
+                        SmallVectorImpl<CfgBlockRef> &list) const final {
+    auto range = CfgTraits::successors(CfgTraits::unwrapRef(block));
+    list.insert(list.end(), CfgTraits::wrapIterator(std::begin(range)),
+                CfgTraits::wrapIterator(std::end(range)));
+  }
+  ArrayRef<CfgBlockRef>
+  getPredecessors(CfgBlockRef block,
+                  SmallVectorImpl<CfgBlockRef> &store) const final {
+    // TODO: Can this be optimized for concrete CFGs that already have the
+    //       "right" in-memory representation of predecessors / successors?
+    store.clear();
+    appendPredecessors(block, store);
+    return store;
+  }
+  ArrayRef<CfgBlockRef>
+  getSuccessors(CfgBlockRef block,
+                SmallVectorImpl<CfgBlockRef> &store) const final {
+    // TODO: Can this be optimized for concrete CFGs that already have the
+    //       "right" in-memory representation of predecessors / successors?
+    store.clear();
+    appendSuccessors(block, store);
+    return store;
+  }
+
+  void appendBlockDefs(CfgBlockRef block,
+                       SmallVectorImpl<CfgValueRef> &list) const final {
+    auto range = CfgTraits::blockdefs(CfgTraits::unwrapRef(block));
+    list.insert(list.end(), CfgTraits::wrapIterator(std::begin(range)),
+                CfgTraits::wrapIterator(std::end(range)));
+  }
+
+  CfgBlockRef getValueDefBlock(CfgValueRef value) const final {
+    return CfgTraits::wrapRef(
+        CfgTraits::getValueDefBlock(CfgTraits::unwrapRef(value)));
+  }
+};
+
+/// \brief Implementation of type-erased "CFG traits"
+///
+/// Note: Do not specialize this template; adjust the CfgTraits type instead
+/// where necessary.
+template <typename CfgTraitsT>
+class CfgPrinterImpl : public CfgPrinter,
+                       private CfgTraitsT::Printer { // empty base optimization
+public:
+  using CfgTraits = CfgTraitsT;
+  using BlockRef = typename CfgTraits::BlockRef;
+  using ValueRef = typename CfgTraits::ValueRef;
+
+public:
+  explicit CfgPrinterImpl(const CfgInterfaceImpl<CfgTraits> &impl)
+      : CfgPrinter(impl), CfgTraitsT::Printer(impl) {}
+
+  void printBlockName(raw_ostream &out, CfgBlockRef block) const final {
+    CfgTraits::Printer::printBlockName(out, CfgTraits::unwrapRef(block));
+  }
+  void printValue(raw_ostream &out, CfgValueRef value) const final {
+    CfgTraits::Printer::printValue(out, CfgTraits::unwrapRef(value));
+  }
+};
+
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_CFGTRAITS_H
Index: llvm/include/llvm/IR/CFG.h
===================================================================
--- llvm/include/llvm/IR/CFG.h
+++ llvm/include/llvm/IR/CFG.h
@@ -25,6 +25,7 @@
 #include "llvm/IR/Function.h"
 #include "llvm/IR/Value.h"
 #include "llvm/Support/Casting.h"
+#include "llvm/Support/CfgTraits.h"
 #include <cassert>
 #include <cstddef>
 #include <iterator>
@@ -398,6 +399,98 @@
   }
 };
 
+//===----------------------------------------------------------------------===//
+// LLVM IR CfgTraits
+//===----------------------------------------------------------------------===//
+
+class IrCfgTraitsBase : public CfgTraitsBase {
+public:
+  using ParentType = Function;
+  using BlockRef = BasicBlock *;
+  using ValueRef = Value *;
+
+  static CfgBlockRef wrapRef(BlockRef block) {
+    return makeOpaque<CfgBlockRefTag>(block);
+  }
+  static CfgValueRef wrapRef(ValueRef block) {
+    return makeOpaque<CfgValueRefTag>(block);
+  }
+  static BlockRef unwrapRef(CfgBlockRef block) {
+    return static_cast<BlockRef>(getOpaque(block));
+  }
+  static ValueRef unwrapRef(CfgValueRef block) {
+    return static_cast<ValueRef>(getOpaque(block));
+  }
+};
+
+/// \brief CFG traits for LLVM IR.
+class IrCfgTraits : public CfgTraits<IrCfgTraitsBase, IrCfgTraits> {
+public:
+  explicit IrCfgTraits(Function * /*parent*/) {}
+
+  static Function *getBlockParent(BasicBlock *block) {
+    return block->getParent();
+  }
+
+  static auto predecessors(BasicBlock *block) {
+    return llvm::predecessors(block);
+  }
+  static auto successors(BasicBlock *block) { return llvm::successors(block); }
+
+  /// Get the defining block of a value if it is an instruction, or null
+  /// otherwise.
+  static BlockRef getValueDefBlock(ValueRef value) {
+    if (auto *instruction = dyn_cast<Instruction>(value))
+      return instruction->getParent();
+    return nullptr;
+  }
+
+  struct block_iterator
+      : iterator_adaptor_base<block_iterator, Function::iterator> {
+    using Base = iterator_adaptor_base<block_iterator, Function::iterator>;
+
+    block_iterator() = default;
+
+    explicit block_iterator(Function::iterator i) : Base(i) {}
+
+    BasicBlock *operator*() const { return &Base::operator*(); }
+  };
+
+  static iterator_range<block_iterator> blocks(Function *function) {
+    return {block_iterator(function->begin()), block_iterator(function->end())};
+  }
+
+  struct value_iterator
+      : iterator_adaptor_base<value_iterator, BasicBlock::iterator> {
+    using Base = iterator_adaptor_base<value_iterator, BasicBlock::iterator>;
+
+    value_iterator() = default;
+
+    explicit value_iterator(BasicBlock::iterator i) : Base(i) {}
+
+    ValueRef operator*() const { return &Base::operator*(); }
+  };
+
+  static iterator_range<value_iterator> blockdefs(BlockRef block) {
+    return {value_iterator(block->begin()), value_iterator(block->end())};
+  }
+
+  struct Printer {
+    explicit Printer(const IrCfgTraits &);
+    ~Printer();
+
+    void printBlockName(raw_ostream &out, BlockRef block) const;
+    void printValue(raw_ostream &out, ValueRef value) const;
+
+  private:
+    mutable std::unique_ptr<ModuleSlotTracker> m_moduleSlotTracker;
+
+    void ensureModuleSlotTracker(const Function &function) const;
+  };
+};
+
+template <> struct CfgTraitsFor<BasicBlock> { using CfgTraits = IrCfgTraits; };
+
 } // end namespace llvm
 
 #endif // LLVM_IR_CFG_H
Index: llvm/include/llvm/CodeGen/MachineCfgTraits.h
===================================================================
--- /dev/null
+++ llvm/include/llvm/CodeGen/MachineCfgTraits.h
@@ -0,0 +1,171 @@
+//===- MachineCfgTraits.h - Traits for Machine IR CFGs ----------*- 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+///
+/// This file defines the MachineCfgTraits to allow generic CFG algorithms to
+/// operate on MachineIR in SSA form.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CODEGEN_MACHINECFGTRAITS_H
+#define LLVM_CODEGEN_MACHINECFGTRAITS_H
+
+#include "llvm/CodeGen/MachineBasicBlock.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/CfgTraits.h"
+
+namespace llvm {
+
+class MachineCfgTraitsBase : public CfgTraitsBase {
+public:
+  using ParentType = MachineFunction;
+  using BlockRef = MachineBasicBlock *;
+  using ValueRef = Register;
+
+  static CfgBlockRef wrapRef(BlockRef block) {
+    return makeOpaque<CfgBlockRefTag>(block);
+  }
+  static CfgValueRef wrapRef(ValueRef value) {
+    // Physical registers are unsupported by design.
+    assert(!value.isValid() || value.isVirtual());
+    uintptr_t wrapped = value.id();
+    assert((wrapped != 0) == value.isValid());
+
+    // Guard against producing values reserved for DenseMap markers. This is de
+    // facto impossible, because it'd require 2^31 virtual registers to be in
+    // use on a 32-bit architecture.
+    assert(wrapped != (uintptr_t)-1 && wrapped != (uintptr_t)-2);
+
+    return makeOpaque<CfgValueRefTag>(reinterpret_cast<void *>(wrapped));
+  }
+  static BlockRef unwrapRef(CfgBlockRef block) {
+    return static_cast<BlockRef>(getOpaque(block));
+  }
+  static ValueRef unwrapRef(CfgValueRef value) {
+    uintptr_t wrapped = reinterpret_cast<uintptr_t>(getOpaque(value));
+    return Register(wrapped);
+  }
+};
+
+/// \brief CFG traits for Machine IR in SSA form.
+class MachineCfgTraits
+    : public CfgTraits<MachineCfgTraitsBase, MachineCfgTraits> {
+private:
+  MachineRegisterInfo *m_regInfo;
+
+public:
+  explicit MachineCfgTraits(MachineFunction *parent)
+      : m_regInfo(&parent->getRegInfo()) {}
+
+  static MachineFunction *getBlockParent(MachineBasicBlock *block) {
+    return block->getParent();
+  }
+
+  struct const_blockref_iterator
+      : iterator_adaptor_base<const_blockref_iterator,
+                              MachineFunction::iterator> {
+    using Base = iterator_adaptor_base<const_blockref_iterator,
+                                       MachineFunction::iterator>;
+
+    const_blockref_iterator() = default;
+
+    explicit const_blockref_iterator(MachineFunction::iterator i) : Base(i) {}
+
+    MachineBasicBlock *operator*() const { return &Base::operator*(); }
+  };
+
+  static iterator_range<const_blockref_iterator>
+  blocks(MachineFunction *function) {
+    return {const_blockref_iterator(function->begin()),
+            const_blockref_iterator(function->end())};
+  }
+
+  static auto predecessors(MachineBasicBlock *block) {
+    return block->predecessors();
+  }
+  static auto successors(MachineBasicBlock *block) {
+    return block->successors();
+  }
+
+  /// Get the defining block of a value.
+  MachineBasicBlock *getValueDefBlock(ValueRef value) const {
+    if (!value)
+      return nullptr;
+    return m_regInfo->getVRegDef(value)->getParent();
+  }
+
+  struct blockdef_iterator
+      : iterator_facade_base<blockdef_iterator, std::forward_iterator_tag,
+                             Register> {
+  private:
+    MachineBasicBlock::instr_iterator m_instr;
+    MachineInstr::mop_iterator m_def;
+
+  public:
+    blockdef_iterator() = default;
+
+    explicit blockdef_iterator(MachineBasicBlock &block)
+        : m_instr(block.instr_begin()) {
+      if (m_instr != block.end())
+        m_def = m_instr->defs().begin();
+    }
+    blockdef_iterator(MachineBasicBlock &block, bool)
+        : m_instr(block.instr_end()), m_def() {}
+
+    bool operator==(const blockdef_iterator &rhs) const {
+      return m_instr == rhs.m_instr && m_def == rhs.m_def;
+    }
+
+    Register operator*() const {
+      assert(m_def->isReg() && !m_def->getSubReg() && m_def->isDef());
+      return m_def->getReg();
+    }
+
+    blockdef_iterator &operator++() {
+      ++m_def;
+
+      while (m_def == m_instr->defs().end()) {
+        ++m_instr;
+        if (m_instr.isEnd()) {
+          m_def = {};
+          return *this;
+        }
+
+        m_def = m_instr->defs().begin();
+      }
+
+      return *this;
+    }
+  };
+
+  static auto blockdefs(MachineBasicBlock *block) {
+    return llvm::make_range(blockdef_iterator(*block),
+                            blockdef_iterator(*block, true));
+  }
+
+  struct Printer {
+    explicit Printer(const MachineCfgTraits &traits)
+        : m_regInfo(traits.m_regInfo) {}
+
+    void printBlockName(raw_ostream &out, MachineBasicBlock *block) const;
+    void printValue(raw_ostream &out, Register value) const;
+
+  private:
+    MachineRegisterInfo *m_regInfo;
+  };
+};
+
+template <> struct CfgTraitsFor<MachineBasicBlock> {
+  using CfgTraits = MachineCfgTraits;
+};
+
+} // namespace llvm
+
+#endif // LLVM_CODEGEN_MACHINECFGTRAITS_H
Index: clang/include/clang/Analysis/Analyses/Dominators.h
===================================================================
--- clang/include/clang/Analysis/Analyses/Dominators.h
+++ clang/include/clang/Analysis/Analyses/Dominators.h
@@ -18,11 +18,100 @@
 #include "llvm/ADT/DepthFirstIterator.h"
 #include "llvm/ADT/GraphTraits.h"
 #include "llvm/ADT/iterator.h"
-#include "llvm/Support/GenericIteratedDominanceFrontier.h"
+#include "llvm/Support/CfgTraits.h"
 #include "llvm/Support/GenericDomTree.h"
 #include "llvm/Support/GenericDomTreeConstruction.h"
+#include "llvm/Support/GenericIteratedDominanceFrontier.h"
 #include "llvm/Support/raw_ostream.h"
 
+namespace clang {
+
+/// Partial CFG traits for MLIR's CFG, without a value type.
+class CfgTraitsBase : public llvm::CfgTraitsBase {
+public:
+  using ParentType = CFG;
+  using BlockRef = CFGBlock *;
+  using ValueRef = void;
+
+  static llvm::CfgBlockRef wrapRef(BlockRef block) {
+    return makeOpaque<llvm::CfgBlockRefTag>(block);
+  }
+  static BlockRef unwrapRef(llvm::CfgBlockRef block) {
+    return static_cast<BlockRef>(getOpaque(block));
+  }
+};
+
+class CfgTraits : public llvm::CfgTraits<CfgTraitsBase, CfgTraits> {
+public:
+  static ParentType *getBlockParent(CFGBlock *block) {
+    return block->getParent();
+  }
+
+  // Clang's CFG contains null pointers for unreachable successors, e.g. when an
+  // if statement's condition is always false, it's 'then' branch is represented
+  // with a nullptr. Account for this in the predecessors / successors
+  // iteration.
+  template <typename BaseIteratorT> struct skip_null_iterator;
+
+  template <typename BaseIteratorT>
+  using skip_null_iterator_base =
+      llvm::iterator_adaptor_base<skip_null_iterator<BaseIteratorT>,
+                                  BaseIteratorT,
+                                  std::bidirectional_iterator_tag>;
+
+  template <typename BaseIteratorT>
+  struct skip_null_iterator : skip_null_iterator_base<BaseIteratorT> {
+    using Base = skip_null_iterator_base<BaseIteratorT>;
+
+    skip_null_iterator() = default;
+    skip_null_iterator(BaseIteratorT it, BaseIteratorT end)
+        : Base(it), m_end(end) {
+      forward();
+    }
+
+    skip_null_iterator &operator++() {
+      ++this->I;
+      forward();
+      return *this;
+    }
+
+    skip_null_iterator &operator--() {
+      do {
+        --this->I;
+      } while (!*this->I);
+      return *this;
+    }
+
+  private:
+    BaseIteratorT m_end;
+
+    void forward() {
+      while (this->I != m_end && !*this->I)
+        ++this->I;
+    }
+  };
+
+  static auto predecessors(CFGBlock *block) {
+    auto range = llvm::inverse_children<CFGBlock *>(block);
+    using iterator = skip_null_iterator<decltype(range.begin())>;
+    return llvm::make_range(iterator(range.begin(), range.end()),
+                            iterator(range.end(), range.end()));
+  }
+
+  static auto successors(CFGBlock *block) {
+    auto range = llvm::children<CFGBlock *>(block);
+    using iterator = skip_null_iterator<decltype(range.begin())>;
+    return llvm::make_range(iterator(range.begin(), range.end()),
+                            iterator(range.end(), range.end()));
+  }
+};
+
+} // namespace clang
+
+template <> struct llvm::CfgTraitsFor<clang::CFGBlock> {
+  using CfgTraits = clang::CfgTraits;
+};
+
 // FIXME: There is no good reason for the domtree to require a print method
 // which accepts an LLVM Module, so remove this (and the method's argument that
 // needs it) when that is fixed.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to