blob: 1c4c2fbdadae95de6d19fb5198f19a654cb9663b [file]
//===- SystemZInsnDirectiveEmitter.cpp - Generate .insn match table -------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend emits a match table for SystemZ .insn directives.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include <string>
using namespace llvm;
namespace {
struct InsnMatchEntry {
std::string Format;
std::string Opcode;
unsigned NumOptionalOperands;
SmallVector<std::string, 8> OperandKinds;
};
static StringRef getFormatName(const Record &Def) {
StringRef AsmString = Def.getValueAsString("AsmString");
if (!AsmString.consume_front(".insn "))
PrintFatalError(&Def, "expected .insn asm string");
return AsmString.take_until([](char C) { return C == ','; });
}
static std::string getMatchClassKind(const Record &Def, const Init *Arg,
unsigned OperandIndex) {
// Obtain record of operand.
const Record *OpRec;
if (const DefInit *DefOp = dyn_cast<DefInit>(Arg))
OpRec = DefOp->getDef();
else if (const DagInit *DagOp = dyn_cast<DagInit>(Arg))
OpRec = DagOp->getOperatorAsDef(Def.getLoc());
else
PrintFatalError(&Def, "Unexpected Init Type (neither def nor dag) in .insn "
"directive operand");
// Get name of ParserMatchClass associated with operand.
StringRef MC =
OpRec->getValueAsDef("ParserMatchClass")->getValueAsString("Name");
// Prepend MCK_ and return.
return "MCK_" + std::string(MC);
}
static InsnMatchEntry buildInsnMatchEntry(const Record &Def, unsigned &MaxNum) {
const DagInit *OutOperands = Def.getValueAsDag("OutOperandList");
const DagInit *InOperands = Def.getValueAsDag("InOperandList");
if (OutOperands->getNumArgs() > 0)
PrintFatalError(&Def, ".insn directive may not have output operands");
unsigned InOps = InOperands->getNumArgs();
if (InOps == 0)
PrintFatalError(&Def, ".insn directive missing encoding operand");
InsnMatchEntry Entry;
Entry.Format = getFormatName(Def).str();
Entry.Opcode = ("SystemZ::" + Def.getName()).str();
for (unsigned I = 0; I < InOps; ++I)
Entry.OperandKinds.push_back(
getMatchClassKind(Def, InOperands->getArg(I), I));
Entry.NumOptionalOperands =
(unsigned)Def.getValueAsInt("NumOptionalOperands");
if (Entry.NumOptionalOperands > InOps)
PrintFatalError(&Def, "NumOptionalOperands exceeds operand count");
if (MaxNum < InOps)
MaxNum = InOps;
return Entry;
}
static void emitInsnDirectiveMatchTable(const RecordKeeper &RK,
raw_ostream &OS) {
emitSourceFileHeader("Match Table for SystemZ .insn directive operand types",
OS);
unsigned MaxOperandCount = 0;
// This will hold all .insn directive definitions (~100 plus margin).
SmallVector<InsnMatchEntry, 128> Entries;
// Collect all InstSystemZ records that have IsInsnDirective set to 1.
for (const Record *Def : RK.getAllDerivedDefinitions("InstSystemZ"))
if (Def->getValueAsBit("IsInsnDirective"))
Entries.push_back(buildInsnMatchEntry(*Def, MaxOperandCount));
// Sort entries by format name.
llvm::sort(Entries, [](const InsnMatchEntry &LHS, const InsnMatchEntry &RHS) {
return LHS.Format < RHS.Format;
});
OS << "constexpr unsigned MAX_INSN_OPERANDNUM = " << MaxOperandCount << ";\n";
OS << "\n";
OS << "struct InsnMatchEntry {\n";
OS << " StringRef Format;\n";
OS << " uint64_t Opcode;\n";
OS << " uint32_t NumOperands;\n";
OS << " uint32_t NumOptionalOperands;\n";
OS << " MatchClassKind OperandKinds[MAX_INSN_OPERANDNUM];\n";
OS << "};\n";
OS << "\n";
OS << "struct CompareInsn {\n";
OS << " bool operator()(const InsnMatchEntry &LHS, StringRef RHS) {\n";
OS << " return LHS.Format < RHS;\n";
OS << " }\n";
OS << " bool operator()(StringRef LHS, const InsnMatchEntry &RHS) {\n";
OS << " return LHS < RHS.Format;\n";
OS << " }\n";
OS << " bool operator()(const InsnMatchEntry &LHS,\n";
OS << " const InsnMatchEntry &RHS) {\n";
OS << " return LHS.Format < RHS.Format;\n";
OS << " }\n";
OS << "};\n";
OS << "\n";
OS << "/* Format, Opcode, NumOperands, NumOptionalOperands, OperandKinds "
"*/\n";
OS << "static InsnMatchEntry InsnMatchTable[] = {\n";
for (const InsnMatchEntry &Entry : Entries) {
OS << " {\"" << Entry.Format << "\", " << Entry.Opcode << ", "
<< Entry.OperandKinds.size() << ", " << Entry.NumOptionalOperands
<< ", {";
for (unsigned I = 0; I < Entry.OperandKinds.size(); ++I) {
if (I != 0)
OS << ", ";
OS << Entry.OperandKinds[I];
}
OS << "}},\n";
}
OS << "};\n";
}
} // namespace
static TableGen::Emitter::Opt X("gen-insn-directive-match-table",
emitInsnDirectiveMatchTable,
"Generate SystemZ .insn match table.");