1//===- SystemZInsnDirectiveEmitter.cpp - Generate .insn match table -------===//
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//
9// This tablegen backend emits a match table for SystemZ .insn directives.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ADT/SmallVector.h"
14#include "llvm/ADT/StringMap.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/TableGen/Error.h"
17#include "llvm/TableGen/Record.h"
18#include "llvm/TableGen/TableGenBackend.h"
19#include <string>
20
21using namespace llvm;
22
23namespace {
24
25struct InsnMatchEntry {
26 std::string Format;
27 std::string Opcode;
28 unsigned NumOptionalOperands;
29 SmallVector<std::string, 8> OperandKinds;
30};
31
32static StringRef getFormatName(const Record &Def) {
33 StringRef AsmString = Def.getValueAsString(FieldName: "AsmString");
34 if (!AsmString.consume_front(Prefix: ".insn "))
35 PrintFatalError(Rec: &Def, Msg: "expected .insn asm string");
36 return AsmString.take_until(F: [](char C) { return C == ','; });
37}
38
39static std::string getMatchClassKind(const Record &Def, const Init *Arg,
40 unsigned OperandIndex) {
41
42 // Obtain record of operand.
43 const Record *OpRec;
44 if (const DefInit *DefOp = dyn_cast<DefInit>(Val: Arg))
45 OpRec = DefOp->getDef();
46 else if (const DagInit *DagOp = dyn_cast<DagInit>(Val: Arg))
47 OpRec = DagOp->getOperatorAsDef(Loc: Def.getLoc());
48 else
49 PrintFatalError(Rec: &Def, Msg: "Unexpected Init Type (neither def nor dag) in .insn "
50 "directive operand");
51
52 // Get name of ParserMatchClass associated with operand.
53 StringRef MC =
54 OpRec->getValueAsDef(FieldName: "ParserMatchClass")->getValueAsString(FieldName: "Name");
55
56 // Prepend MCK_ and return.
57 return "MCK_" + std::string(MC);
58}
59
60static InsnMatchEntry buildInsnMatchEntry(const Record &Def, unsigned &MaxNum) {
61 const DagInit *OutOperands = Def.getValueAsDag(FieldName: "OutOperandList");
62 const DagInit *InOperands = Def.getValueAsDag(FieldName: "InOperandList");
63 if (OutOperands->getNumArgs() > 0)
64 PrintFatalError(Rec: &Def, Msg: ".insn directive may not have output operands");
65 unsigned InOps = InOperands->getNumArgs();
66 if (InOps == 0)
67 PrintFatalError(Rec: &Def, Msg: ".insn directive missing encoding operand");
68
69 InsnMatchEntry Entry;
70 Entry.Format = getFormatName(Def).str();
71 Entry.Opcode = ("SystemZ::" + Def.getName()).str();
72
73 for (unsigned I = 0; I < InOps; ++I)
74 Entry.OperandKinds.push_back(
75 Elt: getMatchClassKind(Def, Arg: InOperands->getArg(Num: I), OperandIndex: I));
76
77 Entry.NumOptionalOperands =
78 (unsigned)Def.getValueAsInt(FieldName: "NumOptionalOperands");
79 if (Entry.NumOptionalOperands > InOps)
80 PrintFatalError(Rec: &Def, Msg: "NumOptionalOperands exceeds operand count");
81
82 if (MaxNum < InOps)
83 MaxNum = InOps;
84
85 return Entry;
86}
87
88static void emitInsnDirectiveMatchTable(const RecordKeeper &RK,
89 raw_ostream &OS) {
90 emitSourceFileHeader(Desc: "Match Table for SystemZ .insn directive operand types",
91 OS);
92 unsigned MaxOperandCount = 0;
93 // This will hold all .insn directive definitions (~100 plus margin).
94 SmallVector<InsnMatchEntry, 128> Entries;
95 // Collect all InstSystemZ records that have IsInsnDirective set to 1.
96 for (const Record *Def : RK.getAllDerivedDefinitions(ClassName: "InstSystemZ"))
97 if (Def->getValueAsBit(FieldName: "IsInsnDirective"))
98 Entries.push_back(Elt: buildInsnMatchEntry(Def: *Def, MaxNum&: MaxOperandCount));
99
100 // Sort entries by format name.
101 llvm::sort(C&: Entries, Comp: [](const InsnMatchEntry &LHS, const InsnMatchEntry &RHS) {
102 return LHS.Format < RHS.Format;
103 });
104
105 OS << "constexpr unsigned MAX_INSN_OPERANDNUM = " << MaxOperandCount << ";\n";
106 OS << "\n";
107 OS << "struct InsnMatchEntry {\n";
108 OS << " StringRef Format;\n";
109 OS << " uint64_t Opcode;\n";
110 OS << " uint32_t NumOperands;\n";
111 OS << " uint32_t NumOptionalOperands;\n";
112 OS << " MatchClassKind OperandKinds[MAX_INSN_OPERANDNUM];\n";
113 OS << "};\n";
114 OS << "\n";
115 OS << "struct CompareInsn {\n";
116 OS << " bool operator()(const InsnMatchEntry &LHS, StringRef RHS) {\n";
117 OS << " return LHS.Format < RHS;\n";
118 OS << " }\n";
119 OS << " bool operator()(StringRef LHS, const InsnMatchEntry &RHS) {\n";
120 OS << " return LHS < RHS.Format;\n";
121 OS << " }\n";
122 OS << " bool operator()(const InsnMatchEntry &LHS,\n";
123 OS << " const InsnMatchEntry &RHS) {\n";
124 OS << " return LHS.Format < RHS.Format;\n";
125 OS << " }\n";
126 OS << "};\n";
127 OS << "\n";
128 OS << "/* Format, Opcode, NumOperands, NumOptionalOperands, OperandKinds "
129 "*/\n";
130 OS << "static InsnMatchEntry InsnMatchTable[] = {\n";
131 for (const InsnMatchEntry &Entry : Entries) {
132 OS << " {\"" << Entry.Format << "\", " << Entry.Opcode << ", "
133 << Entry.OperandKinds.size() << ", " << Entry.NumOptionalOperands
134 << ", {";
135 for (unsigned I = 0; I < Entry.OperandKinds.size(); ++I) {
136 if (I != 0)
137 OS << ", ";
138 OS << Entry.OperandKinds[I];
139 }
140 OS << "}},\n";
141 }
142 OS << "};\n";
143}
144} // namespace
145
146static TableGen::Emitter::Opt X("gen-insn-directive-match-table",
147 emitInsnDirectiveMatchTable,
148 "Generate SystemZ .insn match table.");
149