xref: /netbsd-src/external/apache2/llvm/dist/llvm/utils/TableGen/CodeBeadsGen.cpp (revision 82d56013d7b633d116a93943de88e08335357a7c)
1 //===---------- CodeBeadsGen.cpp - Code Beads Generator -------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // CodeBeads are data fields carrying auxiliary information for instructions.
9 //
10 // Under the hood it's simply implemented by a `bits` field (with arbitrary
11 // length) in each TG instruction description, where this TG backend will
12 // generate a helper function to access it.
13 //
14 // This is especially useful for expressing variable length encoding
15 // instructions and complex addressing modes. Since in those cases each
16 // instruction is usually associated with large amount of information like
17 // addressing mode details used on a specific operand. Instead of retreating to
18 // ad-hoc methods to figure out these information when encoding an instruction,
19 // CodeBeads provide a clean table for the instruction encoder to lookup.
20 //===----------------------------------------------------------------------===//
21 
22 #include "CodeGenTarget.h"
23 #include "llvm/ADT/StringExtras.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/TableGen/Error.h"
26 #include "llvm/TableGen/Record.h"
27 #include "llvm/TableGen/TableGenBackend.h"
28 #include <map>
29 #include <string>
30 #include <vector>
31 using namespace llvm;
32 
33 namespace {
34 
35 class CodeBeadsGen {
36   RecordKeeper &Records;
37 
38 public:
CodeBeadsGen(RecordKeeper & R)39   CodeBeadsGen(RecordKeeper &R) : Records(R) {}
40   void run(raw_ostream &OS);
41 };
42 
run(raw_ostream & OS)43 void CodeBeadsGen::run(raw_ostream &OS) {
44   CodeGenTarget Target(Records);
45   std::vector<Record *> Insts = Records.getAllDerivedDefinitions("Instruction");
46 
47   // For little-endian instruction bit encodings, reverse the bit order
48   Target.reverseBitsForLittleEndianEncoding();
49 
50   ArrayRef<const CodeGenInstruction *> NumberedInstructions =
51       Target.getInstructionsByEnumValue();
52 
53   // Emit function declaration
54   OS << "const uint8_t *llvm::" << Target.getInstNamespace();
55   OS << "::getMCInstrBeads(unsigned Opcode) {\n";
56 
57   // First, get the maximum bit length among all beads. And do some
58   // simple validation
59   unsigned MaxBitLength = 0;
60 
61   for (const CodeGenInstruction *CGI : NumberedInstructions) {
62     Record *R = CGI->TheDef;
63     if (!R->getValue("Beads"))
64       continue;
65 
66     BitsInit *BI = R->getValueAsBitsInit("Beads");
67     if (!BI->isComplete()) {
68       PrintFatalError(R->getLoc(), "Record `" + R->getName() +
69                                        "', bit field 'Beads' is not complete");
70     }
71 
72     MaxBitLength = std::max(MaxBitLength, BI->getNumBits());
73   }
74 
75   // Number of bytes
76   unsigned Parts = MaxBitLength / 8;
77 
78   // Emit instruction base values
79   OS << "  static const uint8_t InstBits[][" << Parts << "] = {\n";
80   for (const CodeGenInstruction *CGI : NumberedInstructions) {
81     Record *R = CGI->TheDef;
82 
83     if (R->getValueAsString("Namespace") == "TargetOpcode" ||
84         !R->getValue("Beads")) {
85       OS << "\t{ 0x0 },\t// ";
86       if (R->getValueAsBit("isPseudo"))
87         OS << "(Pseudo) ";
88       OS << R->getName() << "\n";
89       continue;
90     }
91 
92     BitsInit *BI = R->getValueAsBitsInit("Beads");
93 
94     // Convert to byte array:
95     // [dcba] -> [a][b][c][d]
96     OS << "\t{";
97     for (unsigned p = 0; p < Parts; ++p) {
98       unsigned Right = 8 * p;
99       unsigned Left = Right + 8;
100 
101       uint8_t Value = 0;
102       for (unsigned i = Right; i != Left; ++i) {
103         unsigned Shift = i % 8;
104         if (auto *B = dyn_cast<BitInit>(BI->getBit(i))) {
105           Value |= (static_cast<uint8_t>(B->getValue()) << Shift);
106         } else {
107           PrintFatalError(R->getLoc(), "Record `" + R->getName() +
108                                            "', bit 'Beads[" + Twine(i) +
109                                            "]' is not defined");
110         }
111       }
112 
113       if (p)
114         OS << ',';
115       OS << " 0x";
116       OS.write_hex(Value);
117       OS << "";
118     }
119     OS << " }," << '\t' << "// " << R->getName() << "\n";
120   }
121   OS << "\t{ 0x0 }\n  };\n";
122 
123   // Emit initial function code
124   OS << "  return InstBits[Opcode];\n"
125      << "}\n\n";
126 }
127 
128 } // End anonymous namespace
129 
130 namespace llvm {
131 
EmitCodeBeads(RecordKeeper & RK,raw_ostream & OS)132 void EmitCodeBeads(RecordKeeper &RK, raw_ostream &OS) {
133   emitSourceFileHeader("Machine Code Beads", OS);
134   CodeBeadsGen(RK).run(OS);
135 }
136 
137 } // namespace llvm
138