mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-25 12:12:47 +01:00
138 lines
4.3 KiB
C++
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
|