Re-commit: [globalisel] Tablegen-erate current Register Bank Information

Summary:
Adds a RegisterBank tablegen class that can be used to declare the register
banks and an associated tablegen pass to generate the necessary code.

Changes since last commit:
The new tablegen pass is now correctly guarded by LLVM_BUILD_GLOBAL_ISEL and
this should fix the buildbots however it may not be the whole fix. The previous
buildbot failures suggest there may be a memory bug lurking that I'm unable to
reproduce (including when using asan) or spot in the source. If they re-occur
on this commit then I'll need assistance from the bot owners to track it down.

Reviewers: t.p.northover, ab, rovka, qcolombet

Reviewed By: qcolombet

Subscribers: aditya_nandakumar, rengolin, kristof.beyls, vkalintiris, mgorny, dberris, llvm-commits, rovka

Differential Revision: https://reviews.llvm.org/D27338

llvm-svn: 292367
This commit is contained in:
Daniel Sanders 2017-01-18 14:17:50 +00:00
parent df7c6ef96f
commit 517b61cb69
16 changed files with 438 additions and 194 deletions

View File

@ -42,7 +42,7 @@ private:
public:
RegisterBank(unsigned ID, const char *Name, unsigned Size,
const uint32_t *ContainedRegClasses);
const uint32_t *ContainedRegClasses, unsigned NumRegClasses);
/// Get the identifier of this register bank.
unsigned getID() const { return ID; }

View File

@ -0,0 +1,16 @@
//===- RegisterBank.td - Register bank definitions ---------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
class RegisterBank<string name, list<RegisterClass> classes> {
string Name = name;
list<RegisterClass> RegisterClasses = classes;
}

View File

@ -1344,4 +1344,5 @@ include "llvm/Target/TargetSelectionDAG.td"
//===----------------------------------------------------------------------===//
// Pull in the common support for Global ISel generation.
//
include "llvm/Target/GlobalISel/RegisterBank.td"
include "llvm/Target/TargetGlobalISel.td"

View File

@ -19,10 +19,11 @@ using namespace llvm;
const unsigned RegisterBank::InvalidID = UINT_MAX;
RegisterBank::RegisterBank(unsigned ID, const char *Name, unsigned Size,
const uint32_t *CoveredClasses)
RegisterBank::RegisterBank(
unsigned ID, const char *Name, unsigned Size,
const uint32_t *CoveredClasses, unsigned NumRegClasses)
: ID(ID), Name(Name), Size(Size) {
ContainedRegClasses.resize(200);
ContainedRegClasses.resize(NumRegClasses);
ContainedRegClasses.setBitsInMask(CoveredClasses);
}

View File

@ -127,6 +127,7 @@ def HasV8_2aOps : SubtargetFeature<"v8.2a", "HasV8_2aOps", "true",
//===----------------------------------------------------------------------===//
include "AArch64RegisterInfo.td"
include "AArch64RegisterBanks.td"
include "AArch64CallingConvention.td"
//===----------------------------------------------------------------------===//

View File

@ -16,204 +16,81 @@
#endif
namespace llvm {
namespace AArch64 {
const uint32_t GPRCoverageData[] = {
// Classes 0-31
(1u << AArch64::GPR32allRegClassID) | (1u << AArch64::GPR32RegClassID) |
(1u << AArch64::GPR32spRegClassID) |
(1u << AArch64::GPR32commonRegClassID) |
(1u << AArch64::GPR32sponlyRegClassID) |
(1u << AArch64::GPR64allRegClassID) | (1u << AArch64::GPR64RegClassID) |
(1u << AArch64::GPR64spRegClassID) |
(1u << AArch64::GPR64commonRegClassID) |
(1u << AArch64::tcGPR64RegClassID) |
(1u << AArch64::GPR64sponlyRegClassID),
// Classes 32-63
0,
// FIXME: The entries below this point can be safely removed once this is
// tablegenerated. It's only needed because of the hardcoded register class
// limit.
// Classes 64-96
0,
// Classes 97-128
0,
// Classes 129-160
0,
// Classes 161-192
0,
// Classes 193-224
0,
};
const uint32_t FPRCoverageData[] = {
// Classes 0-31
(1u << AArch64::FPR8RegClassID) | (1u << AArch64::FPR16RegClassID) |
(1u << AArch64::FPR32RegClassID) | (1u << AArch64::FPR64RegClassID) |
(1u << AArch64::DDRegClassID) | (1u << AArch64::FPR128RegClassID) |
(1u << AArch64::FPR128_loRegClassID) | (1u << AArch64::DDDRegClassID) |
(1u << AArch64::DDDDRegClassID),
// Classes 32-63
(1u << (AArch64::QQRegClassID - 32)) |
(1u << (AArch64::QQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
(1u
<< (AArch64::
QQQ_with_qsub1_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub2_in_FPR128_loRegClassID -
32)) |
(1u << (AArch64::QQQQRegClassID - 32)) |
(1u << (AArch64::QQQQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQQQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQQQ_with_qsub2_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQQQ_with_qsub3_in_FPR128_loRegClassID - 32)) |
(1u
<< (AArch64::
QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub1_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQQ_with_qsub2_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub2_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQQ_with_qsub1_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQQQ_with_qsub0_in_FPR128_lo_and_QQQQ_with_qsub3_in_FPR128_loRegClassID -
32)) |
(1u
<< (AArch64::
QQ_with_qsub0_in_FPR128_lo_and_QQ_with_qsub1_in_FPR128_loRegClassID -
32)) |
(1u << (AArch64::QQQRegClassID - 32)) |
(1u << (AArch64::QQQ_with_qsub0_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQQ_with_qsub1_in_FPR128_loRegClassID - 32)) |
(1u << (AArch64::QQQ_with_qsub2_in_FPR128_loRegClassID - 32)) |
(1u
<< (AArch64::
QQQ_with_qsub0_in_FPR128_lo_and_QQQ_with_qsub1_in_FPR128_loRegClassID -
32)),
// FIXME: The entries below this point can be safely removed once this
// is tablegenerated. It's only needed because of the hardcoded register
// class limit.
// Classes 64-96
0,
// Classes 97-128
0,
// Classes 129-160
0,
// Classes 161-192
0,
// Classes 193-224
0,
};
const uint32_t CCRCoverageData[] = {
// Classes 0-31
1u << AArch64::CCRRegClassID,
// Classes 32-63
0,
// FIXME: The entries below this point can be safely removed once this
// is tablegenerated. It's only needed because of the hardcoded register
// class limit.
// Classes 64-96
0,
// Classes 97-128
0,
// Classes 129-160
0,
// Classes 161-192
0,
// Classes 193-224
0,
};
RegisterBank GPRRegBank(AArch64::GPRRegBankID, "GPR", 64, GPRCoverageData);
RegisterBank FPRRegBank(AArch64::FPRRegBankID, "FPR", 512, FPRCoverageData);
RegisterBank CCRRegBank(AArch64::CCRRegBankID, "CCR", 32, CCRCoverageData);
} // end namespace AArch64
RegisterBank *AArch64GenRegisterBankInfo::RegBanks[] = {
&AArch64::GPRRegBank, &AArch64::FPRRegBank, &AArch64::CCRRegBank};
RegisterBankInfo::PartialMapping AArch64GenRegisterBankInfo::PartMappings[]{
/* StartIdx, Length, RegBank */
// 0: GPR 32-bit value.
{0, 32, AArch64::GPRRegBank},
// 1: GPR 64-bit value.
{0, 64, AArch64::GPRRegBank},
// 2: FPR 32-bit value.
// 0: FPR 32-bit value.
{0, 32, AArch64::FPRRegBank},
// 3: FPR 64-bit value.
// 1: FPR 64-bit value.
{0, 64, AArch64::FPRRegBank},
// 4: FPR 128-bit value.
// 2: FPR 128-bit value.
{0, 128, AArch64::FPRRegBank},
// 5: FPR 256-bit value.
// 3: FPR 256-bit value.
{0, 256, AArch64::FPRRegBank},
// 6: FPR 512-bit value.
{0, 512, AArch64::FPRRegBank}};
// 4: FPR 512-bit value.
{0, 512, AArch64::FPRRegBank},
// 5: GPR 32-bit value.
{0, 32, AArch64::GPRRegBank},
// 6: GPR 64-bit value.
{0, 64, AArch64::GPRRegBank},
};
// ValueMappings.
RegisterBankInfo::ValueMapping AArch64GenRegisterBankInfo::ValMappings[]{
/* BreakDown, NumBreakDowns */
// 3-operands instructions (all binary operations should end up with one of
// those mapping).
// 0: GPR 32-bit value. <-- This must match First3OpsIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
// 3: GPR 64-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
// 6: FPR 32-bit value.
// 0: FPR 32-bit value. <-- This must match First3OpsIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
// 9: FPR 64-bit value.
// 3: FPR 64-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
// 12: FPR 128-bit value.
// 6: FPR 128-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR128 - PMI_Min], 1},
// 15: FPR 256-bit value.
// 9: FPR 256-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR256 - PMI_Min], 1},
// 18: FPR 512-bit value. <-- This must match Last3OpsIdx.
// 12: FPR 512-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR512 - PMI_Min], 1},
// 15: GPR 32-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
// 18: GPR 64-bit value. <-- This must match Last3OpsIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
// Cross register bank copies.
// 21: GPR 32-bit value to FPR 32-bit value. <-- This must match
// 21: FPR 32-bit value to GPR 32-bit value. <-- This must match
// FirstCrossRegCpyIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
// 23: FPR 64-bit value to GPR 64-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
// 25: FPR 128-bit value to GPR 128-bit value (invalid)
{nullptr, 1},
{nullptr, 1},
// 27: FPR 256-bit value to GPR 256-bit value (invalid)
{nullptr, 1},
{nullptr, 1},
// 29: FPR 512-bit value to GPR 512-bit value (invalid)
{nullptr, 1},
{nullptr, 1},
// 31: GPR 32-bit value to FPR 32-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
// 23: GPR 64-bit value to FPR 64-bit value.
// 33: GPR 64-bit value to FPR 64-bit value. <-- This must match
// LastCrossRegCpyIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
// 25: FPR 32-bit value to GPR 32-bit value.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR32 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR32 - PMI_Min], 1},
// 27: FPR 64-bit value to GPR 64-bit value. <-- This must match
// LastCrossRegCpyIdx.
{&AArch64GenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1},
{&AArch64GenRegisterBankInfo::PartMappings[PMI_GPR64 - PMI_Min], 1}
};
bool AArch64GenRegisterBankInfo::checkPartialMap(unsigned Idx,
@ -301,9 +178,9 @@ AArch64GenRegisterBankInfo::getValueMapping(PartialMappingIdx RBIdx,
AArch64GenRegisterBankInfo::PartialMappingIdx
AArch64GenRegisterBankInfo::BankIDToCopyMapIdx[]{
PMI_FirstGPR, // GPR
PMI_FirstFPR, // FPR
PMI_None, // CCR
PMI_FirstFPR, // FPR
PMI_FirstGPR, // GPR
};
const RegisterBankInfo::ValueMapping *

View File

@ -21,6 +21,9 @@
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetSubtargetInfo.h"
#define GET_TARGET_REGBANK_IMPL
#include "AArch64GenRegisterBank.inc"
// This file will be TableGen'ed at some point.
#include "AArch64GenRegisterBankInfo.def"
@ -30,9 +33,6 @@ using namespace llvm;
#error "You shouldn't build this"
#endif
AArch64GenRegisterBankInfo::AArch64GenRegisterBankInfo()
: RegisterBankInfo(RegBanks, AArch64::NumRegisterBanks) {}
AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI)
: AArch64GenRegisterBankInfo() {
static bool AlreadyInit = false;

View File

@ -16,40 +16,30 @@
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
#define GET_REGBANK_DECLARATIONS
#include "AArch64GenRegisterBank.inc"
namespace llvm {
class TargetRegisterInfo;
namespace AArch64 {
enum {
GPRRegBankID = 0, /// General Purpose Registers: W, X.
FPRRegBankID = 1, /// Floating Point/Vector Registers: B, H, S, D, Q.
CCRRegBankID = 2, /// Conditional register: NZCV.
NumRegisterBanks
};
} // End AArch64 namespace.
class AArch64GenRegisterBankInfo : public RegisterBankInfo {
private:
static RegisterBank *RegBanks[];
protected:
AArch64GenRegisterBankInfo();
enum PartialMappingIdx {
PMI_None = -1,
PMI_GPR32 = 1,
PMI_GPR64,
PMI_FPR32,
PMI_FPR32 = 1,
PMI_FPR64,
PMI_FPR128,
PMI_FPR256,
PMI_FPR512,
PMI_GPR32,
PMI_GPR64,
PMI_FirstGPR = PMI_GPR32,
PMI_LastGPR = PMI_GPR64,
PMI_FirstFPR = PMI_FPR32,
PMI_LastFPR = PMI_FPR512,
PMI_Min = PMI_FirstGPR,
PMI_Min = PMI_FirstFPR,
};
static RegisterBankInfo::PartialMapping PartMappings[];
@ -61,7 +51,7 @@ protected:
Last3OpsIdx = 18,
DistanceBetweenRegBanks = 3,
FirstCrossRegCpyIdx = 21,
LastCrossRegCpyIdx = 27,
LastCrossRegCpyIdx = 33,
DistanceBetweenCrossRegCpy = 2
};
@ -90,6 +80,9 @@ protected:
/// register bank with a size of \p Size.
static const RegisterBankInfo::ValueMapping *
getCopyMapping(unsigned DstBankID, unsigned SrcBankID, unsigned Size);
#define GET_TARGET_REGBANK_CLASS
#include "AArch64GenRegisterBank.inc"
};
/// This class provides the information for the target register banks.

View File

@ -0,0 +1,20 @@
//=- AArch64RegisterBank.td - Describe the AArch64 Banks -----*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
/// General Purpose Registers: W, X.
def GPRRegBank : RegisterBank<"GPR", [GPR64all]>;
/// Floating Point/Vector Registers: B, H, S, D, Q.
def FPRRegBank : RegisterBank<"FPR", [QQQQ]>;
/// Conditional register: NZCV.
def CCRRegBank : RegisterBank<"CCR", [CCR]>;

View File

@ -14,6 +14,7 @@ tablegen(LLVM AArch64GenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM AArch64GenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM AArch64GenSystemOperands.inc -gen-searchable-tables)
if(LLVM_BUILD_GLOBAL_ISEL)
tablegen(LLVM AArch64GenRegisterBank.inc -gen-register-bank)
tablegen(LLVM AArch64GenGlobalISel.inc -gen-global-isel)
endif()

View File

@ -55,7 +55,9 @@ const uint32_t GPRCoverageData[] = {
0,
};
RegisterBank GPRRegBank(ARM::GPRRegBankID, "GPRB", 32, ARM::GPRCoverageData);
// FIXME: The 200 will be replaced by the number of register classes when this is
// tablegenerated.
RegisterBank GPRRegBank(ARM::GPRRegBankID, "GPRB", 32, ARM::GPRCoverageData, 200);
RegisterBank *RegBanks[] = {&GPRRegBank};
RegisterBankInfo::PartialMapping GPRPartialMapping{0, 32, GPRRegBank};

View File

@ -0,0 +1,16 @@
//===- RegisterBank.td - Register bank definitions ---------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
class RegisterBank<string name, list<RegisterClass> classes> {
string Name = name;
list<RegisterClass> RegisterClasses = classes;
}

View File

@ -27,6 +27,7 @@ add_tablegen(llvm-tblgen LLVM
IntrinsicEmitter.cpp
OptParserEmitter.cpp
PseudoLoweringEmitter.cpp
RegisterBankEmitter.cpp
RegisterInfoEmitter.cpp
SearchableTableEmitter.cpp
SubtargetEmitter.cpp

View File

@ -0,0 +1,309 @@
//===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting a description of a target
// register bank for a code generator.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "CodeGenRegisters.h"
#define DEBUG_TYPE "register-bank-emitter"
using namespace llvm;
namespace {
class RegisterBank {
/// A vector of register classes that are included in the register bank.
typedef std::vector<const CodeGenRegisterClass *> RegisterClassesTy;
private:
const Record &TheDef;
/// The register classes that are covered by the register bank.
RegisterClassesTy RCs;
/// The register class with the largest register size.
const CodeGenRegisterClass *RCWithLargestRegsSize;
public:
RegisterBank(const Record &TheDef)
: TheDef(TheDef), RCs(), RCWithLargestRegsSize(nullptr) {}
/// Get the human-readable name for the bank.
std::string getName() const { return TheDef.getValueAsString("Name"); }
/// Get the name of the enumerator in the ID enumeration.
std::string getEnumeratorName() const { return (TheDef.getName() + "ID").str(); }
/// Get the name of the array holding the register class coverage data;
std::string getCoverageArrayName() const {
return (TheDef.getName() + "CoverageData").str();
}
/// Get the name of the global instance variable.
StringRef getInstanceVarName() const { return TheDef.getName(); }
const Record &getDef() const { return TheDef; }
/// Get the register classes listed in the RegisterBank.RegisterClasses field.
std::vector<const CodeGenRegisterClass *>
getExplictlySpecifiedRegisterClasses(
CodeGenRegBank &RegisterClassHierarchy) const {
std::vector<const CodeGenRegisterClass *> RCs;
for (const auto &RCDef : getDef().getValueAsListOfDefs("RegisterClasses"))
RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef));
return RCs;
}
/// Add a register class to the bank without duplicates.
void addRegisterClass(const CodeGenRegisterClass *RC) {
if (std::find_if(RCs.begin(), RCs.end(),
[&RC](const CodeGenRegisterClass *X) {
return X == RC;
}) != RCs.end())
return;
// FIXME? We really want the register size rather than the spill size
// since the spill size may be bigger on some targets with
// limited load/store instructions. However, we don't store the
// register size anywhere (we could sum the sizes of the subregisters
// but there may be additional bits too) and we can't derive it from
// the VT's reliably due to Untyped.
if (RCWithLargestRegsSize == nullptr)
RCWithLargestRegsSize = RC;
else if (RCWithLargestRegsSize->SpillSize < RC->SpillSize)
RCWithLargestRegsSize = RC;
assert(RCWithLargestRegsSize && "RC was nullptr?");
RCs.emplace_back(RC);
}
const CodeGenRegisterClass *getRCWithLargestRegsSize() const {
return RCWithLargestRegsSize;
}
iterator_range<typename RegisterClassesTy::const_iterator>
register_classes() const {
return llvm::make_range(RCs.begin(), RCs.end());
}
};
class RegisterBankEmitter {
private:
RecordKeeper &Records;
CodeGenRegBank RegisterClassHierarchy;
void emitHeader(raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks);
void emitBaseClassDefinition(raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks);
void emitBaseClassImplementation(raw_ostream &OS, const StringRef TargetName,
std::vector<RegisterBank> &Banks);
public:
RegisterBankEmitter(RecordKeeper &R)
: Records(R), RegisterClassHierarchy(Records) {}
void run(raw_ostream &OS);
};
} // end anonymous namespace
/// Emit code to declare the ID enumeration and external global instance
/// variables.
void RegisterBankEmitter::emitHeader(raw_ostream &OS,
const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
// <Target>RegisterBankInfo.h
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n"
<< "enum {\n";
for (const auto &Bank : Banks)
OS << " " << Bank.getEnumeratorName() << ",\n";
OS << " NumRegisterBanks,\n"
<< "};\n"
<< "} // end namespace " << TargetName << "\n"
<< "} // end namespace llvm\n";
}
/// Emit declarations of the <Target>GenRegisterBankInfo class.
void RegisterBankEmitter::emitBaseClassDefinition(
raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
OS << "private:\n"
<< " static RegisterBank *RegBanks[];\n\n"
<< "protected:\n"
<< " " << TargetName << "GenRegisterBankInfo();\n"
<< "\n";
}
/// Visit each register class belonging to the given register bank.
///
/// A class belongs to the bank iff any of these apply:
/// * It is explicitly specified
/// * It is a subclass of a class that is a member.
/// * It is a class containing subregisters of the registers of a class that
/// is a member. This is known as a subreg-class.
///
/// This function must be called for each explicitly specified register class.
///
/// \param RC The register class to search.
/// \param Kind A debug string containing the path the visitor took to reach RC.
/// \param VisitFn The action to take for each class visited. It may be called
/// multiple times for a given class if there are multiple paths
/// to the class.
static void visitRegisterBankClasses(
CodeGenRegBank &RegisterClassHierarchy, const CodeGenRegisterClass *RC,
const Twine Kind,
std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn) {
// Visit each explicitly named class.
VisitFn(RC, Kind.str());
for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) {
Twine TmpKind = Kind + " (" + PossibleSubclass.getName() + ")";
// Visit each subclass of an explicitly named class.
if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass))
visitRegisterBankClasses(RegisterClassHierarchy, &PossibleSubclass,
TmpKind + " " + RC->getName() + " subclass",
VisitFn);
// Visit each class that contains only subregisters of RC with a common
// subregister-index.
//
// More precisely, PossibleSubclass is a subreg-class iff Reg:SubIdx is in
// PossibleSubclass for all registers Reg from RC using any
// subregister-index SubReg
for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) {
BitVector BV(RegisterClassHierarchy.getRegClasses().size());
PossibleSubclass.getSuperRegClasses(&SubIdx, BV);
if (BV.test(RC->EnumValue)) {
Twine TmpKind2 = TmpKind + " " + RC->getName() +
" class-with-subregs: " + RC->getName();
VisitFn(&PossibleSubclass, TmpKind2.str());
}
}
}
}
void RegisterBankEmitter::emitBaseClassImplementation(
raw_ostream &OS, StringRef TargetName,
std::vector<RegisterBank> &Banks) {
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n";
for (const auto &Bank : Banks) {
std::vector<std::vector<const CodeGenRegisterClass *>> RCsGroupedByWord(
(RegisterClassHierarchy.getRegClasses().size() + 31) / 32);
for (const auto &RC : Bank.register_classes())
RCsGroupedByWord[RC->EnumValue / 32].push_back(RC);
OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n";
unsigned LowestIdxInWord = 0;
for (const auto &RCs : RCsGroupedByWord) {
OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) << "\n";
for (const auto &RC : RCs) {
Twine QualifiedRegClassID =
TargetName + "::" + RC->getName() + "RegClassID";
OS << " (1u << (" << QualifiedRegClassID << " - "
<< LowestIdxInWord << ")) |\n";
}
OS << " 0,\n";
LowestIdxInWord += 32;
}
OS << "};\n";
}
OS << "\n";
for (const auto &Bank : Banks) {
Twine QualifiedBankID = TargetName + "::" + Bank.getEnumeratorName();
unsigned Size = Bank.getRCWithLargestRegsSize()->SpillSize;
OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
<< QualifiedBankID << ", /* Name */ \"" << Bank.getName()
<< "\", /* Size */ " << Size << ", "
<< "/* CoveredRegClasses */ " << Bank.getCoverageArrayName()
<< ", /* NumRegClasses */ "
<< RegisterClassHierarchy.getRegClasses().size() << ");\n";
}
OS << "} // end namespace " << TargetName << "\n"
<< "\n";
OS << "RegisterBank *" << TargetName
<< "GenRegisterBankInfo::RegBanks[] = {\n";
for (const auto &Bank : Banks)
OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n";
OS << "};\n\n";
OS << TargetName << "GenRegisterBankInfo::" << TargetName
<< "GenRegisterBankInfo()\n"
<< " : RegisterBankInfo(RegBanks, " << TargetName
<< "::NumRegisterBanks) {\n"
<< " // Assert that RegBank indices match their ID's\n"
<< " unsigned Index = 0;\n"
<< "#ifndef NDEBUG\n"
<< " for (const auto &RB : RegBanks)\n"
<< " assert(Index++ == RB->getID() && \"Index != ID\");\n"
<< "#endif // NDEBUG\n"
<< "}\n"
<< "} // end namespace llvm\n";
}
void RegisterBankEmitter::run(raw_ostream &OS) {
std::vector<Record*> Targets = Records.getAllDerivedDefinitions("Target");
if (Targets.size() != 1)
PrintFatalError("ERROR: Too many or too few subclasses of Target defined!");
StringRef TargetName = Targets[0]->getName();
std::vector<RegisterBank> Banks;
for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {
RegisterBank Bank(*V);
for (const CodeGenRegisterClass *RC :
Bank.getExplictlySpecifiedRegisterClasses(RegisterClassHierarchy)) {
visitRegisterBankClasses(
RegisterClassHierarchy, RC, "explicit",
[&Bank](const CodeGenRegisterClass *RC, StringRef Kind) {
DEBUG(dbgs() << "Added " << RC->getName() << "(" << Kind << ")\n");
Bank.addRegisterClass(RC);
});
}
Banks.push_back(Bank);
}
emitSourceFileHeader("Register Bank Source Fragments", OS);
OS << "#ifdef GET_REGBANK_DECLARATIONS\n"
<< "#undef GET_REGBANK_DECLARATIONS\n";
emitHeader(OS, TargetName, Banks);
OS << "#endif // GET_REGBANK_DECLARATIONS\n\n"
<< "#ifdef GET_TARGET_REGBANK_CLASS\n"
<< "#undef GET_TARGET_REGBANK_CLASS\n";
emitBaseClassDefinition(OS, TargetName, Banks);
OS << "#endif // GET_TARGET_REGBANK_CLASS\n\n"
<< "#ifdef GET_TARGET_REGBANK_IMPL\n"
<< "#undef GET_TARGET_REGBANK_IMPL\n";
emitBaseClassImplementation(OS, TargetName, Banks);
OS << "#endif // GET_TARGET_REGBANK_IMPL\n";
}
namespace llvm {
void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS) {
RegisterBankEmitter(RK).run(OS);
}
} // end namespace llvm

View File

@ -46,6 +46,7 @@ enum ActionType {
GenAttributes,
GenSearchableTables,
GenGlobalISel,
GenRegisterBank,
};
namespace {
@ -94,7 +95,9 @@ namespace {
clEnumValN(GenSearchableTables, "gen-searchable-tables",
"Generate generic binary-searchable table"),
clEnumValN(GenGlobalISel, "gen-global-isel",
"Generate GlobalISel selector")));
"Generate GlobalISel selector"),
clEnumValN(GenRegisterBank, "gen-register-bank",
"Generate registers bank descriptions")));
cl::opt<std::string>
Class("class", cl::desc("Print Enum list for this class"),
@ -182,6 +185,8 @@ bool LLVMTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
break;
case GenGlobalISel:
EmitGlobalISel(Records, OS);
case GenRegisterBank:
EmitRegisterBank(Records, OS);
break;
}

View File

@ -81,6 +81,7 @@ void EmitCTags(RecordKeeper &RK, raw_ostream &OS);
void EmitAttributes(RecordKeeper &RK, raw_ostream &OS);
void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS);
void EmitGlobalISel(RecordKeeper &RK, raw_ostream &OS);
void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS);
} // End llvm namespace