raw_ostream: << operator for callables with raw_ostream argument

This is a revised version of r254655 which uses a Printable wrapper
class to avoid ambiguous overload problems.

Differential Revision: http://reviews.llvm.org/D14348

llvm-svn: 254681
This commit is contained in:
Matthias Braun 2015-12-04 01:31:59 +00:00
parent 580b6572b5
commit c07cbc8d3c
5 changed files with 126 additions and 140 deletions

View File

@ -0,0 +1,52 @@
//===--- Printable.h - Print function helpers -------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the Printable struct.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_PRINTABLE_H
#define LLVM_SUPPORT_PRINTABLE_H
#include <functional>
namespace llvm {
class raw_ostream;
/// Simple wrapper around std::function<void(raw_ostream&)>.
/// This class is usefull to construct print helpers for raw_ostream.
///
/// Example:
/// Printable PrintRegister(unsigned Register) {
/// return Printable([Register](raw_ostream &OS) {
/// OS << getRegisterName(Register);
/// }
/// }
/// ... OS << PrintRegister(Register); ...
///
/// Implementation note: Ideally this would just be a typedef, but doing so
/// leads to operator << being ambiguous as function has matching constructors
/// in some STL versions. I have seen the problem on gcc 4.6 libstdc++ and
/// microsoft STL.
class Printable {
public:
std::function<void(raw_ostream &OS)> Print;
Printable(const std::function<void(raw_ostream &OS)> Print)
: Print(Print) {}
};
static inline raw_ostream &operator<<(raw_ostream &OS, const Printable &P) {
P.Print(OS);
return OS;
}
}
#endif

View File

@ -22,6 +22,7 @@
#include "llvm/IR/CallingConv.h"
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Printable.h"
#include <cassert>
#include <functional>
@ -932,7 +933,6 @@ struct VirtReg2IndexFunctor : public std::unary_function<unsigned, unsigned> {
}
};
/// Helper class for printing registers on a raw_ostream.
/// Prints virtual and physical registers with or without a TRI instance.
///
/// The format is:
@ -943,24 +943,10 @@ struct VirtReg2IndexFunctor : public std::unary_function<unsigned, unsigned> {
/// %physreg17 - a physical register when no TRI instance given.
///
/// Usage: OS << PrintReg(Reg, TRI) << '\n';
///
class PrintReg {
const TargetRegisterInfo *TRI;
unsigned Reg;
unsigned SubIdx;
public:
explicit PrintReg(unsigned reg, const TargetRegisterInfo *tri = nullptr,
unsigned subidx = 0)
: TRI(tri), Reg(reg), SubIdx(subidx) {}
void print(raw_ostream&) const;
};
Printable PrintReg(unsigned Reg, const TargetRegisterInfo *TRI = nullptr,
unsigned SubRegIdx = 0);
static inline raw_ostream &operator<<(raw_ostream &OS, const PrintReg &PR) {
PR.print(OS);
return OS;
}
/// Helper class for printing register units on a raw_ostream.
/// Create Printable object to print register units on a \ref raw_ostream.
///
/// Register units are named after their root registers:
///
@ -968,54 +954,14 @@ static inline raw_ostream &operator<<(raw_ostream &OS, const PrintReg &PR) {
/// FP0~ST7 - Dual roots.
///
/// Usage: OS << PrintRegUnit(Unit, TRI) << '\n';
///
class PrintRegUnit {
protected:
const TargetRegisterInfo *TRI;
unsigned Unit;
public:
PrintRegUnit(unsigned unit, const TargetRegisterInfo *tri)
: TRI(tri), Unit(unit) {}
void print(raw_ostream&) const;
};
Printable PrintRegUnit(unsigned Unit, const TargetRegisterInfo *TRI);
static inline raw_ostream &operator<<(raw_ostream &OS, const PrintRegUnit &PR) {
PR.print(OS);
return OS;
}
/// \brief Create Printable object to print virtual registers and physical
/// registers on a \ref raw_ostream.
Printable PrintVRegOrUnit(unsigned VRegOrUnit, const TargetRegisterInfo *TRI);
/// It is often convenient to track virtual registers and
/// physical register units in the same list.
class PrintVRegOrUnit : protected PrintRegUnit {
public:
PrintVRegOrUnit(unsigned VRegOrUnit, const TargetRegisterInfo *tri)
: PrintRegUnit(VRegOrUnit, tri) {}
void print(raw_ostream&) const;
};
static inline raw_ostream &operator<<(raw_ostream &OS,
const PrintVRegOrUnit &PR) {
PR.print(OS);
return OS;
}
/// Helper class for printing lane masks.
///
/// They are currently printed out as hexadecimal numbers.
/// Usage: OS << PrintLaneMask(Mask);
class PrintLaneMask {
protected:
LaneBitmask LaneMask;
public:
PrintLaneMask(LaneBitmask LaneMask)
: LaneMask(LaneMask) {}
void print(raw_ostream&) const;
};
static inline raw_ostream &operator<<(raw_ostream &OS, const PrintLaneMask &P) {
P.print(OS);
return OS;
}
/// Create Printable object to print LaneBitmasks on a \ref raw_ostream.
Printable PrintLaneMask(LaneBitmask LaneMask);
} // End llvm namespace

View File

@ -47,6 +47,7 @@
#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Printable.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
@ -805,33 +806,17 @@ bool RegAllocPBQP::runOnMachineFunction(MachineFunction &MF) {
return true;
}
namespace {
// A helper class for printing node and register info in a consistent way
class PrintNodeInfo {
public:
typedef PBQP::RegAlloc::PBQPRAGraph Graph;
typedef PBQP::RegAlloc::PBQPRAGraph::NodeId NodeId;
PrintNodeInfo(NodeId NId, const Graph &G) : G(G), NId(NId) {}
void print(raw_ostream &OS) const {
/// Create Printable object for node and register info.
static Printable PrintNodeInfo(PBQP::RegAlloc::PBQPRAGraph::NodeId NId,
const PBQP::RegAlloc::PBQPRAGraph &G) {
return Printable([NId, &G](raw_ostream &OS) {
const MachineRegisterInfo &MRI = G.getMetadata().MF.getRegInfo();
const TargetRegisterInfo *TRI = MRI.getTargetRegisterInfo();
unsigned VReg = G.getNodeMetadata(NId).getVReg();
const char *RegClassName = TRI->getRegClassName(MRI.getRegClass(VReg));
OS << NId << " (" << RegClassName << ':' << PrintReg(VReg, TRI) << ')';
}
private:
const Graph &G;
NodeId NId;
};
inline raw_ostream &operator<<(raw_ostream &OS, const PrintNodeInfo &PR) {
PR.print(OS);
return OS;
});
}
} // anonymous namespace
void PBQP::RegAlloc::PBQPRAGraph::dump(raw_ostream &OS) const {
for (auto NId : nodeIds()) {

View File

@ -22,6 +22,7 @@
#include "llvm/IR/Intrinsics.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/GraphWriter.h"
#include "llvm/Support/Printable.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetIntrinsicInfo.h"
@ -369,25 +370,14 @@ const char *SDNode::getIndexedModeName(ISD::MemIndexedMode AM) {
}
}
namespace {
class PrintNodeId {
const SDNode &Node;
public:
explicit PrintNodeId(const SDNode &Node)
: Node(Node) {}
void print(raw_ostream &OS) const {
static Printable PrintNodeId(const SDNode &Node) {
return Printable([&Node](raw_ostream &OS) {
#ifndef NDEBUG
OS << 't' << Node.PersistentId;
#else
OS << (const void*)&Node;
#endif
}
};
static inline raw_ostream &operator<<(raw_ostream &OS, const PrintNodeId &P) {
P.print(OS);
return OS;
}
});
}
void SDNode::dump() const { dump(nullptr); }

View File

@ -40,58 +40,71 @@ TargetRegisterInfo::TargetRegisterInfo(const TargetRegisterInfoDesc *ID,
TargetRegisterInfo::~TargetRegisterInfo() {}
void PrintReg::print(raw_ostream &OS) const {
if (!Reg)
OS << "%noreg";
else if (TargetRegisterInfo::isStackSlot(Reg))
OS << "SS#" << TargetRegisterInfo::stackSlot2Index(Reg);
else if (TargetRegisterInfo::isVirtualRegister(Reg))
OS << "%vreg" << TargetRegisterInfo::virtReg2Index(Reg);
else if (TRI && Reg < TRI->getNumRegs())
OS << '%' << TRI->getName(Reg);
else
OS << "%physreg" << Reg;
if (SubIdx) {
if (TRI)
OS << ':' << TRI->getSubRegIndexName(SubIdx);
namespace llvm {
Printable PrintReg(unsigned Reg, const TargetRegisterInfo *TRI,
unsigned SubIdx) {
return Printable([Reg, TRI, SubIdx](raw_ostream &OS) {
if (!Reg)
OS << "%noreg";
else if (TargetRegisterInfo::isStackSlot(Reg))
OS << "SS#" << TargetRegisterInfo::stackSlot2Index(Reg);
else if (TargetRegisterInfo::isVirtualRegister(Reg))
OS << "%vreg" << TargetRegisterInfo::virtReg2Index(Reg);
else if (TRI && Reg < TRI->getNumRegs())
OS << '%' << TRI->getName(Reg);
else
OS << ":sub(" << SubIdx << ')';
}
OS << "%physreg" << Reg;
if (SubIdx) {
if (TRI)
OS << ':' << TRI->getSubRegIndexName(SubIdx);
else
OS << ":sub(" << SubIdx << ')';
}
});
}
void PrintRegUnit::print(raw_ostream &OS) const {
// Generic printout when TRI is missing.
if (!TRI) {
OS << "Unit~" << Unit;
return;
}
Printable PrintRegUnit(unsigned Unit, const TargetRegisterInfo *TRI) {
return Printable([Unit, TRI](raw_ostream &OS) {
// Generic printout when TRI is missing.
if (!TRI) {
OS << "Unit~" << Unit;
return;
}
// Check for invalid register units.
if (Unit >= TRI->getNumRegUnits()) {
OS << "BadUnit~" << Unit;
return;
}
// Check for invalid register units.
if (Unit >= TRI->getNumRegUnits()) {
OS << "BadUnit~" << Unit;
return;
}
// Normal units have at least one root.
MCRegUnitRootIterator Roots(Unit, TRI);
assert(Roots.isValid() && "Unit has no roots.");
OS << TRI->getName(*Roots);
for (++Roots; Roots.isValid(); ++Roots)
OS << '~' << TRI->getName(*Roots);
// Normal units have at least one root.
MCRegUnitRootIterator Roots(Unit, TRI);
assert(Roots.isValid() && "Unit has no roots.");
OS << TRI->getName(*Roots);
for (++Roots; Roots.isValid(); ++Roots)
OS << '~' << TRI->getName(*Roots);
});
}
void PrintVRegOrUnit::print(raw_ostream &OS) const {
if (TRI && TRI->isVirtualRegister(Unit)) {
OS << "%vreg" << TargetRegisterInfo::virtReg2Index(Unit);
return;
}
PrintRegUnit::print(OS);
Printable PrintVRegOrUnit(unsigned Unit, const TargetRegisterInfo *TRI) {
return Printable([Unit, TRI](raw_ostream &OS) {
if (TRI && TRI->isVirtualRegister(Unit)) {
OS << "%vreg" << TargetRegisterInfo::virtReg2Index(Unit);
} else {
OS << PrintRegUnit(Unit, TRI);
}
});
}
void PrintLaneMask::print(raw_ostream &OS) const {
OS << format("%08X", LaneMask);
Printable PrintLaneMask(LaneBitmask LaneMask) {
return Printable([LaneMask](raw_ostream &OS) {
OS << format("%08X", LaneMask);
});
}
} // End of llvm namespace
/// getAllocatableClass - Return the maximal subclass of the given register
/// class that is alloctable, or NULL.
const TargetRegisterClass *