diff options
Diffstat (limited to 'llvm/utils/TableGen/CodeBeadsGen.cpp')
-rw-r--r-- | llvm/utils/TableGen/CodeBeadsGen.cpp | 137 |
1 files changed, 137 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/CodeBeadsGen.cpp b/llvm/utils/TableGen/CodeBeadsGen.cpp new file mode 100644 index 000000000000..18a6d6d19eb2 --- /dev/null +++ b/llvm/utils/TableGen/CodeBeadsGen.cpp @@ -0,0 +1,137 @@ +//===---------- 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 |