Skip to content

Commit c0cdd22

Browse files
committed
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
1 parent 84048e2 commit c0cdd22

File tree

12 files changed

+1002
-1
lines changed

12 files changed

+1002
-1
lines changed

clang/include/clang/Analysis/Analyses/Dominators.h

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,100 @@
1818
#include "llvm/ADT/DepthFirstIterator.h"
1919
#include "llvm/ADT/GraphTraits.h"
2020
#include "llvm/ADT/iterator.h"
21-
#include "llvm/Support/GenericIteratedDominanceFrontier.h"
21+
#include "llvm/Support/CfgTraits.h"
2222
#include "llvm/Support/GenericDomTree.h"
2323
#include "llvm/Support/GenericDomTreeConstruction.h"
24+
#include "llvm/Support/GenericIteratedDominanceFrontier.h"
2425
#include "llvm/Support/raw_ostream.h"
2526

27+
namespace clang {
28+
29+
/// Partial CFG traits for MLIR's CFG, without a value type.
30+
class CfgTraitsBase : public llvm::CfgTraitsBase {
31+
public:
32+
using ParentType = CFG;
33+
using BlockRef = CFGBlock *;
34+
using ValueRef = void;
35+
36+
static llvm::CfgBlockRef wrapRef(BlockRef block) {
37+
return makeOpaque<llvm::CfgBlockRefTag>(block);
38+
}
39+
static BlockRef unwrapRef(llvm::CfgBlockRef block) {
40+
return static_cast<BlockRef>(getOpaque(block));
41+
}
42+
};
43+
44+
class CfgTraits : public llvm::CfgTraits<CfgTraitsBase, CfgTraits> {
45+
public:
46+
static ParentType *getBlockParent(CFGBlock *block) {
47+
return block->getParent();
48+
}
49+
50+
// Clang's CFG contains null pointers for unreachable successors, e.g. when an
51+
// if statement's condition is always false, it's 'then' branch is represented
52+
// with a nullptr. Account for this in the predecessors / successors
53+
// iteration.
54+
template <typename BaseIteratorT> struct skip_null_iterator;
55+
56+
template <typename BaseIteratorT>
57+
using skip_null_iterator_base =
58+
llvm::iterator_adaptor_base<skip_null_iterator<BaseIteratorT>,
59+
BaseIteratorT,
60+
std::bidirectional_iterator_tag>;
61+
62+
template <typename BaseIteratorT>
63+
struct skip_null_iterator : skip_null_iterator_base<BaseIteratorT> {
64+
using Base = skip_null_iterator_base<BaseIteratorT>;
65+
66+
skip_null_iterator() = default;
67+
skip_null_iterator(BaseIteratorT it, BaseIteratorT end)
68+
: Base(it), m_end(end) {
69+
forward();
70+
}
71+
72+
skip_null_iterator &operator++() {
73+
++this->I;
74+
forward();
75+
return *this;
76+
}
77+
78+
skip_null_iterator &operator--() {
79+
do {
80+
--this->I;
81+
} while (!*this->I);
82+
return *this;
83+
}
84+
85+
private:
86+
BaseIteratorT m_end;
87+
88+
void forward() {
89+
while (this->I != m_end && !*this->I)
90+
++this->I;
91+
}
92+
};
93+
94+
static auto predecessors(CFGBlock *block) {
95+
auto range = llvm::inverse_children<CFGBlock *>(block);
96+
using iterator = skip_null_iterator<decltype(range.begin())>;
97+
return llvm::make_range(iterator(range.begin(), range.end()),
98+
iterator(range.end(), range.end()));
99+
}
100+
101+
static auto successors(CFGBlock *block) {
102+
auto range = llvm::children<CFGBlock *>(block);
103+
using iterator = skip_null_iterator<decltype(range.begin())>;
104+
return llvm::make_range(iterator(range.begin(), range.end()),
105+
iterator(range.end(), range.end()));
106+
}
107+
};
108+
109+
} // namespace clang
110+
111+
template <> struct llvm::CfgTraitsFor<clang::CFGBlock> {
112+
using CfgTraits = clang::CfgTraits;
113+
};
114+
26115
// FIXME: There is no good reason for the domtree to require a print method
27116
// which accepts an LLVM Module, so remove this (and the method's argument that
28117
// needs it) when that is fixed.
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
//===- MachineCfgTraits.h - Traits for Machine IR CFGs ----------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
/// \file
9+
///
10+
/// This file defines the MachineCfgTraits to allow generic CFG algorithms to
11+
/// operate on MachineIR in SSA form.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#ifndef LLVM_CODEGEN_MACHINECFGTRAITS_H
16+
#define LLVM_CODEGEN_MACHINECFGTRAITS_H
17+
18+
#include "llvm/CodeGen/MachineBasicBlock.h"
19+
#include "llvm/CodeGen/MachineFunction.h"
20+
#include "llvm/CodeGen/MachineInstr.h"
21+
#include "llvm/CodeGen/MachineRegisterInfo.h"
22+
#include "llvm/Support/CfgTraits.h"
23+
24+
namespace llvm {
25+
26+
class MachineCfgTraitsBase : public CfgTraitsBase {
27+
public:
28+
using ParentType = MachineFunction;
29+
using BlockRef = MachineBasicBlock *;
30+
using ValueRef = Register;
31+
32+
static CfgBlockRef wrapRef(BlockRef block) {
33+
return makeOpaque<CfgBlockRefTag>(block);
34+
}
35+
static CfgValueRef wrapRef(ValueRef value) {
36+
// Physical registers are unsupported by design.
37+
assert(!value.isValid() || value.isVirtual());
38+
uintptr_t wrapped = value.id();
39+
assert((wrapped != 0) == value.isValid());
40+
41+
// Guard against producing values reserved for DenseMap markers. This is de
42+
// facto impossible, because it'd require 2^31 virtual registers to be in
43+
// use on a 32-bit architecture.
44+
assert(wrapped != (uintptr_t)-1 && wrapped != (uintptr_t)-2);
45+
46+
return makeOpaque<CfgValueRefTag>(reinterpret_cast<void *>(wrapped));
47+
}
48+
static BlockRef unwrapRef(CfgBlockRef block) {
49+
return static_cast<BlockRef>(getOpaque(block));
50+
}
51+
static ValueRef unwrapRef(CfgValueRef value) {
52+
uintptr_t wrapped = reinterpret_cast<uintptr_t>(getOpaque(value));
53+
return Register(wrapped);
54+
}
55+
};
56+
57+
/// \brief CFG traits for Machine IR in SSA form.
58+
class MachineCfgTraits
59+
: public CfgTraits<MachineCfgTraitsBase, MachineCfgTraits> {
60+
private:
61+
MachineRegisterInfo *m_regInfo;
62+
63+
public:
64+
explicit MachineCfgTraits(MachineFunction *parent)
65+
: m_regInfo(&parent->getRegInfo()) {}
66+
67+
static MachineFunction *getBlockParent(MachineBasicBlock *block) {
68+
return block->getParent();
69+
}
70+
71+
struct const_blockref_iterator
72+
: iterator_adaptor_base<const_blockref_iterator,
73+
MachineFunction::iterator> {
74+
using Base = iterator_adaptor_base<const_blockref_iterator,
75+
MachineFunction::iterator>;
76+
77+
const_blockref_iterator() = default;
78+
79+
explicit const_blockref_iterator(MachineFunction::iterator i) : Base(i) {}
80+
81+
MachineBasicBlock *operator*() const { return &Base::operator*(); }
82+
};
83+
84+
static iterator_range<const_blockref_iterator>
85+
blocks(MachineFunction *function) {
86+
return {const_blockref_iterator(function->begin()),
87+
const_blockref_iterator(function->end())};
88+
}
89+
90+
static auto predecessors(MachineBasicBlock *block) {
91+
return block->predecessors();
92+
}
93+
static auto successors(MachineBasicBlock *block) {
94+
return block->successors();
95+
}
96+
97+
/// Get the defining block of a value.
98+
MachineBasicBlock *getValueDefBlock(ValueRef value) const {
99+
if (!value)
100+
return nullptr;
101+
return m_regInfo->getVRegDef(value)->getParent();
102+
}
103+
104+
struct blockdef_iterator
105+
: iterator_facade_base<blockdef_iterator, std::forward_iterator_tag,
106+
Register> {
107+
private:
108+
MachineBasicBlock::instr_iterator m_instr;
109+
MachineInstr::mop_iterator m_def;
110+
111+
public:
112+
blockdef_iterator() = default;
113+
114+
explicit blockdef_iterator(MachineBasicBlock &block)
115+
: m_instr(block.instr_begin()) {
116+
if (m_instr != block.end())
117+
m_def = m_instr->defs().begin();
118+
}
119+
blockdef_iterator(MachineBasicBlock &block, bool)
120+
: m_instr(block.instr_end()), m_def() {}
121+
122+
bool operator==(const blockdef_iterator &rhs) const {
123+
return m_instr == rhs.m_instr && m_def == rhs.m_def;
124+
}
125+
126+
Register operator*() const {
127+
assert(m_def->isReg() && !m_def->getSubReg() && m_def->isDef());
128+
return m_def->getReg();
129+
}
130+
131+
blockdef_iterator &operator++() {
132+
++m_def;
133+
134+
while (m_def == m_instr->defs().end()) {
135+
++m_instr;
136+
if (m_instr.isEnd()) {
137+
m_def = {};
138+
return *this;
139+
}
140+
141+
m_def = m_instr->defs().begin();
142+
}
143+
144+
return *this;
145+
}
146+
};
147+
148+
static auto blockdefs(MachineBasicBlock *block) {
149+
return llvm::make_range(blockdef_iterator(*block),
150+
blockdef_iterator(*block, true));
151+
}
152+
153+
struct Printer {
154+
explicit Printer(const MachineCfgTraits &traits)
155+
: m_regInfo(traits.m_regInfo) {}
156+
157+
void printBlockName(raw_ostream &out, MachineBasicBlock *block) const;
158+
void printValue(raw_ostream &out, Register value) const;
159+
160+
private:
161+
MachineRegisterInfo *m_regInfo;
162+
};
163+
};
164+
165+
template <> struct CfgTraitsFor<MachineBasicBlock> {
166+
using CfgTraits = MachineCfgTraits;
167+
};
168+
169+
} // namespace llvm
170+
171+
#endif // LLVM_CODEGEN_MACHINECFGTRAITS_H

llvm/include/llvm/IR/CFG.h

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "llvm/IR/Function.h"
2626
#include "llvm/IR/Value.h"
2727
#include "llvm/Support/Casting.h"
28+
#include "llvm/Support/CfgTraits.h"
2829
#include <cassert>
2930
#include <cstddef>
3031
#include <iterator>
@@ -398,6 +399,98 @@ template <> struct GraphTraits<Inverse<const Function*>> :
398399
}
399400
};
400401

402+
//===----------------------------------------------------------------------===//
403+
// LLVM IR CfgTraits
404+
//===----------------------------------------------------------------------===//
405+
406+
class IrCfgTraitsBase : public CfgTraitsBase {
407+
public:
408+
using ParentType = Function;
409+
using BlockRef = BasicBlock *;
410+
using ValueRef = Value *;
411+
412+
static CfgBlockRef wrapRef(BlockRef block) {
413+
return makeOpaque<CfgBlockRefTag>(block);
414+
}
415+
static CfgValueRef wrapRef(ValueRef block) {
416+
return makeOpaque<CfgValueRefTag>(block);
417+
}
418+
static BlockRef unwrapRef(CfgBlockRef block) {
419+
return static_cast<BlockRef>(getOpaque(block));
420+
}
421+
static ValueRef unwrapRef(CfgValueRef block) {
422+
return static_cast<ValueRef>(getOpaque(block));
423+
}
424+
};
425+
426+
/// \brief CFG traits for LLVM IR.
427+
class IrCfgTraits : public CfgTraits<IrCfgTraitsBase, IrCfgTraits> {
428+
public:
429+
explicit IrCfgTraits(Function * /*parent*/) {}
430+
431+
static Function *getBlockParent(BasicBlock *block) {
432+
return block->getParent();
433+
}
434+
435+
static auto predecessors(BasicBlock *block) {
436+
return llvm::predecessors(block);
437+
}
438+
static auto successors(BasicBlock *block) { return llvm::successors(block); }
439+
440+
/// Get the defining block of a value if it is an instruction, or null
441+
/// otherwise.
442+
static BlockRef getValueDefBlock(ValueRef value) {
443+
if (auto *instruction = dyn_cast<Instruction>(value))
444+
return instruction->getParent();
445+
return nullptr;
446+
}
447+
448+
struct block_iterator
449+
: iterator_adaptor_base<block_iterator, Function::iterator> {
450+
using Base = iterator_adaptor_base<block_iterator, Function::iterator>;
451+
452+
block_iterator() = default;
453+
454+
explicit block_iterator(Function::iterator i) : Base(i) {}
455+
456+
BasicBlock *operator*() const { return &Base::operator*(); }
457+
};
458+
459+
static iterator_range<block_iterator> blocks(Function *function) {
460+
return {block_iterator(function->begin()), block_iterator(function->end())};
461+
}
462+
463+
struct value_iterator
464+
: iterator_adaptor_base<value_iterator, BasicBlock::iterator> {
465+
using Base = iterator_adaptor_base<value_iterator, BasicBlock::iterator>;
466+
467+
value_iterator() = default;
468+
469+
explicit value_iterator(BasicBlock::iterator i) : Base(i) {}
470+
471+
ValueRef operator*() const { return &Base::operator*(); }
472+
};
473+
474+
static iterator_range<value_iterator> blockdefs(BlockRef block) {
475+
return {value_iterator(block->begin()), value_iterator(block->end())};
476+
}
477+
478+
struct Printer {
479+
explicit Printer(const IrCfgTraits &);
480+
~Printer();
481+
482+
void printBlockName(raw_ostream &out, BlockRef block) const;
483+
void printValue(raw_ostream &out, ValueRef value) const;
484+
485+
private:
486+
mutable std::unique_ptr<ModuleSlotTracker> m_moduleSlotTracker;
487+
488+
void ensureModuleSlotTracker(const Function &function) const;
489+
};
490+
};
491+
492+
template <> struct CfgTraitsFor<BasicBlock> { using CfgTraits = IrCfgTraits; };
493+
401494
} // end namespace llvm
402495

403496
#endif // LLVM_IR_CFG_H

0 commit comments

Comments
 (0)