1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00
llvm-mirror/utils/TableGen/CodeBeadsGen.cpp
Min-Yih Hsu fe0580f6c0 [M68k][TableGen](1/8) TableGen related changes
- Add a new TableGen backend: CodeBeads
 - Add support to generate logical operand information

For the first item, it is currently a workaround of M68k's (complex)
instruction encoding. A typical architecture, especially CISC one like
X86, normally uses `MCInstrDesc::TSFlags` to carry instruction encoding
info. However, at the early days of M68k backend development, we found
it difficult to fit every possible encoding into the 64-bit
`MCInstrDesc::TSFlags`. Therefore CodeBeads was invented to provide
an alternative, arbitrary length container for instruciton encoding
info. However, in the long term we incline not to use a new TG
backend for less common pattern like what we encountered in M68k. A bug
has been created to host to discussion on migrating from CodeBeads to
more concise solution: https://bugs.llvm.org/show_bug.cgi?id=48792

The second item was also served for similar purpose. It created utility
functions that tell you the index of a `MachineOperand` in a
`MachineInst` given a logical operand index. In normal cases a logical
operand is the same as `MachineOperand`, but for operands using complex
addressing mode a logical operand might be consisting of multiple
`MachineOperand`. The TableGen-ed `getLogicalOperandIdx`, for instance,
can give you the mapping between these two concepts. Nevertheless, we
hope to remove this feature in the future if possible. Since it's not
really useful for the targets supported by LLVM now either.

Authors: myhsu, m4yers, glaubitz

Differential Revision: https://reviews.llvm.org/D88385
2021-03-08 12:30:56 -08:00

138 lines
4.3 KiB
C++

//===---------- CodeBeadsGen.cpp - Code Beads Generator -------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// CodeBeads are data fields carrying auxiliary information for instructions.
//
// Under the hood it's simply implemented by a `bits` field (with arbitrary
// length) in each TG instruction description, where this TG backend will
// generate a helper function to access it.
//
// This is especially useful for expressing variable length encoding
// instructions and complex addressing modes. Since in those cases each
// instruction is usually associated with large amount of information like
// addressing mode details used on a specific operand. Instead of retreating to
// ad-hoc methods to figure out these information when encoding an instruction,
// CodeBeads provide a clean table for the instruction encoder to lookup.
//===----------------------------------------------------------------------===//
#include "CodeGenTarget.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <map>
#include <string>
#include <vector>
using namespace llvm;
namespace {
class CodeBeadsGen {
RecordKeeper &Records;
public:
CodeBeadsGen(RecordKeeper &R) : Records(R) {}
void run(raw_ostream &OS);
};
void CodeBeadsGen::run(raw_ostream &OS) {
CodeGenTarget Target(Records);
std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction");
// For little-endian instruction bit encodings, reverse the bit order
Target.reverseBitsForLittleEndianEncoding();
ArrayRef<const CodeGenInstruction *> NumberedInstructions =
Target.getInstructionsByEnumValue();
// Emit function declaration
OS << "const uint8_t *llvm::" << Target.getInstNamespace();
OS << "::getMCInstrBeads(unsigned Opcode) {\n";
// First, get the maximum bit length among all beads. And do some
// simple validation
unsigned MaxBitLength = 0;
for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
if (!R->getValue("Beads"))
continue;
BitsInit *BI = R->getValueAsBitsInit("Beads");
if (!BI->isComplete()) {
PrintFatalError(R->getLoc(), "Record `" + R->getName() +
"', bit field 'Beads' is not complete");
}
MaxBitLength = std::max(MaxBitLength, BI->getNumBits());
}
// Number of bytes
unsigned Parts = MaxBitLength / 8;
// Emit instruction base values
OS << " static const uint8_t InstBits[][" << Parts << "] = {\n";
for (const CodeGenInstruction *CGI : NumberedInstructions) {
Record *R = CGI->TheDef;
if (R->getValueAsString("Namespace") == "TargetOpcode" ||
!R->getValue("Beads")) {
OS << "\t{ 0x0 },\t// ";
if (R->getValueAsBit("isPseudo"))
OS << "(Pseudo) ";
OS << R->getName() << "\n";
continue;
}
BitsInit *BI = R->getValueAsBitsInit("Beads");
// Convert to byte array:
// [dcba] -> [a][b][c][d]
OS << "\t{";
for (unsigned p = 0; p < Parts; ++p) {
unsigned Right = 8 * p;
unsigned Left = Right + 8;
uint8_t Value = 0;
for (unsigned i = Right; i != Left; ++i) {
unsigned Shift = i % 8;
if (auto *B = dyn_cast<BitInit>(BI->getBit(i))) {
Value |= (static_cast<uint8_t>(B->getValue()) << Shift);
} else {
PrintFatalError(R->getLoc(), "Record `" + R->getName() +
"', bit 'Beads[" + Twine(i) +
"]' is not defined");
}
}
if (p)
OS << ',';
OS << " 0x";
OS.write_hex(Value);
OS << "";
}
OS << " }," << '\t' << "// " << R->getName() << "\n";
}
OS << "\t{ 0x0 }\n };\n";
// Emit initial function code
OS << " return InstBits[Opcode];\n"
<< "}\n\n";
}
} // End anonymous namespace
namespace llvm {
void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS) {
emitSourceFileHeader("Machine Code Beads", OS);
CodeBeadsGen(RK).run(OS);
}
} // namespace llvm