aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm14/utils/TableGen/CodeBeadsGen.cpp
blob: 18a6d6d19eb232ff71ac5eac951fb5e01ac2184e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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