| 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 | |
| 21 | using namespace llvm; |
| 22 | |
| 23 | namespace { |
| 24 | |
| 25 | struct InsnMatchEntry { |
| 26 | std::string Format; |
| 27 | std::string Opcode; |
| 28 | unsigned NumOptionalOperands; |
| 29 | SmallVector<std::string, 8> OperandKinds; |
| 30 | }; |
| 31 | |
| 32 | static 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 | |
| 39 | static 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 | |
| 60 | static 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 | |
| 88 | static 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 | |
| 146 | static TableGen::Emitter::Opt X("gen-insn-directive-match-table" , |
| 147 | emitInsnDirectiveMatchTable, |
| 148 | "Generate SystemZ .insn match table." ); |
| 149 | |