1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

Introduce CfgTraits abstraction

The CfgTraits abstraction simplfies writing algorithms that are
generic over the type of CFG, and enables writing such algorithms
as regular non-template code that operates on opaque references
to CFG blocks and values.

Implementations of CfgTraits provide operations on the concrete
CFG types, e.g. `IrCfgTraits::BlockRef` is `BasicBlock *`.

CfgInterface is an abstract base class which provides operations
on opaque types CfgBlockRef and CfgValueRef. Those opaque types
encapsulate a `void *`, but the meaning depends on the concrete
CFG type. For example, MachineCfgTraits -- for use with MachineIR
in SSA form -- encodes a Register inside CfgValueRef. Converting
between concrete references and opaque/generic ones is done by
CfgTraits::{fromGeneric,toGeneric}. Convenience methods
CfgTraits::{un}wrap{Iterator,Range} are available as well.

Writing algorithms in terms of CfgInterface adds some overhead
(virtual method calls, plus in same cases it removes the
opportunity to inline iterators), but can be much more convenient
since generic algorithms can be written as non-templates.

This patch adds implementations of CfgTraits for all CFGs on
which dominator trees are calculated, so that the dominator
tree can be ported to this machinery. Only IrCfgTraits (LLVM IR)
and MachineCfgTraits (Machine IR in SSA form) are complete, the
other implementations are limited to the absolute minimum
required to make the upcoming dominator tree changes work.

v5:
- fix MachineCfgTraits::blockdef_iterator and allow it to iterate over
  the instructions in a bundle
- use MachineBasicBlock::printName

v6:
- implement predecessors/successors for all CfgTraits implementations
- fix error in unwrapRange
- rename toGeneric/fromGeneric into wrapRef/unwrapRef to have naming
  that is consistent with {wrap,unwrap}{Iterator,Range}
- use getVRegDef instead of getUniqueVRegDef

v7:
- std::forward fix in wrapping_iterator
- fix typos

v8:
- cleanup operators on CfgOpaqueType
- address other review comments

Change-Id: Ia75f4f268fded33fca11218a7d578c9aec1f3f4d

Differential Revision: https://reviews.llvm.org/D83088
This commit is contained in:
Nicolai Hähnle 2020-10-20 13:50:52 +02:00
parent b2aaec2555
commit 58c9429d2a
10 changed files with 874 additions and 0 deletions

View File

@ -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

View File

@ -25,6 +25,7 @@
#include "llvm/IR/Function.h" #include "llvm/IR/Function.h"
#include "llvm/IR/Value.h" #include "llvm/IR/Value.h"
#include "llvm/Support/Casting.h" #include "llvm/Support/Casting.h"
#include "llvm/Support/CfgTraits.h"
#include <cassert> #include <cassert>
#include <cstddef> #include <cstddef>
#include <iterator> #include <iterator>
@ -398,6 +399,98 @@ template <> struct GraphTraits<Inverse<const Function*>> :
} }
}; };
//===----------------------------------------------------------------------===//
// 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 } // end namespace llvm
#endif // LLVM_IR_CFG_H #endif // LLVM_IR_CFG_H

View File

@ -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

View File

@ -71,6 +71,7 @@ add_llvm_component_library(LLVMCodeGen
MachineBlockFrequencyInfo.cpp MachineBlockFrequencyInfo.cpp
MachineBlockPlacement.cpp MachineBlockPlacement.cpp
MachineBranchProbabilityInfo.cpp MachineBranchProbabilityInfo.cpp
MachineCfgTraits.cpp
MachineCombiner.cpp MachineCombiner.cpp
MachineCopyPropagation.cpp MachineCopyPropagation.cpp
MachineCSE.cpp MachineCSE.cpp

View File

@ -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);
}

56
lib/IR/CFG.cpp Normal file
View File

@ -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);
}
}

View File

@ -4,6 +4,7 @@ add_llvm_component_library(LLVMCore
Attributes.cpp Attributes.cpp
AutoUpgrade.cpp AutoUpgrade.cpp
BasicBlock.cpp BasicBlock.cpp
CFG.cpp
Comdat.cpp Comdat.cpp
ConstantFold.cpp ConstantFold.cpp
ConstantRange.cpp ConstantRange.cpp

View File

@ -97,6 +97,7 @@ add_llvm_component_library(LLVMSupport
BranchProbability.cpp BranchProbability.cpp
BuryPointer.cpp BuryPointer.cpp
CachePruning.cpp CachePruning.cpp
CfgTraits.cpp
circular_raw_ostream.cpp circular_raw_ostream.cpp
Chrono.cpp Chrono.cpp
COM.cpp COM.cpp

14
lib/Support/CfgTraits.cpp Normal file
View File

@ -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() {}

View File

@ -18,9 +18,42 @@
#include "VPlan.h" #include "VPlan.h"
#include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/GraphTraits.h"
#include "llvm/IR/Dominators.h" #include "llvm/IR/Dominators.h"
#include "llvm/Support/CfgTraits.h"
namespace llvm { 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 /// Template specialization of the standard LLVM dominator tree utility for
/// VPBlockBases. /// VPBlockBases.
using VPDominatorTree = DomTreeBase<VPBlockBase>; using VPDominatorTree = DomTreeBase<VPBlockBase>;