//===---------- 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 #include #include 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 Insts = Records.getAllDerivedDefinitions("Instruction"); // For little-endian instruction bit encodings, reverse the bit order Target.reverseBitsForLittleEndianEncoding(); ArrayRef 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(BI->getBit(i))) { Value |= (static_cast(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