xref: /llvm-project/mlir/tools/mlir-tblgen/BytecodeDialectGen.cpp (revision f4d758634305304c0deb49a4ed3f99180a2488ea)
109115580SJacques Pienaar //===- BytecodeDialectGen.cpp - Dialect bytecode read/writer gen  ---------===//
209115580SJacques Pienaar //
309115580SJacques Pienaar // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409115580SJacques Pienaar // See https://llvm.org/LICENSE.txt for license information.
509115580SJacques Pienaar // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609115580SJacques Pienaar //
709115580SJacques Pienaar //===----------------------------------------------------------------------===//
809115580SJacques Pienaar 
909115580SJacques Pienaar #include "mlir/Support/IndentedOstream.h"
1009115580SJacques Pienaar #include "mlir/TableGen/GenInfo.h"
1109115580SJacques Pienaar #include "llvm/ADT/MapVector.h"
1209115580SJacques Pienaar #include "llvm/ADT/STLExtras.h"
13*f4d75863SJakub Kuderski #include "llvm/ADT/SmallVectorExtras.h"
1409115580SJacques Pienaar #include "llvm/Support/CommandLine.h"
1509115580SJacques Pienaar #include "llvm/Support/FormatVariadic.h"
1609115580SJacques Pienaar #include "llvm/TableGen/Error.h"
1709115580SJacques Pienaar #include "llvm/TableGen/Record.h"
1809115580SJacques Pienaar #include <regex>
1909115580SJacques Pienaar 
2009115580SJacques Pienaar using namespace llvm;
2109115580SJacques Pienaar 
22bccd37f6SRahul Joshi static cl::OptionCategory dialectGenCat("Options for -gen-bytecode");
23bccd37f6SRahul Joshi static cl::opt<std::string>
24bccd37f6SRahul Joshi     selectedBcDialect("bytecode-dialect", cl::desc("The dialect to gen for"),
25bccd37f6SRahul Joshi                       cl::cat(dialectGenCat), cl::CommaSeparated);
2609115580SJacques Pienaar 
2709115580SJacques Pienaar namespace {
2809115580SJacques Pienaar 
2909115580SJacques Pienaar /// Helper class to generate C++ bytecode parser helpers.
3009115580SJacques Pienaar class Generator {
3109115580SJacques Pienaar public:
3209115580SJacques Pienaar   Generator(raw_ostream &output) : output(output) {}
3309115580SJacques Pienaar 
3409115580SJacques Pienaar   /// Returns whether successfully emitted attribute/type parsers.
35a5dfcccdSRahul Joshi   void emitParse(StringRef kind, const Record &x);
3609115580SJacques Pienaar 
3709115580SJacques Pienaar   /// Returns whether successfully emitted attribute/type printers.
3809115580SJacques Pienaar   void emitPrint(StringRef kind, StringRef type,
39a5dfcccdSRahul Joshi                  ArrayRef<std::pair<int64_t, const Record *>> vec);
4009115580SJacques Pienaar 
4109115580SJacques Pienaar   /// Emits parse dispatch table.
42a5dfcccdSRahul Joshi   void emitParseDispatch(StringRef kind, ArrayRef<const Record *> vec);
4309115580SJacques Pienaar 
4409115580SJacques Pienaar   /// Emits print dispatch table.
4509115580SJacques Pienaar   void emitPrintDispatch(StringRef kind, ArrayRef<std::string> vec);
4609115580SJacques Pienaar 
4709115580SJacques Pienaar private:
4809115580SJacques Pienaar   /// Emits parse calls to construct given kind.
4909115580SJacques Pienaar   void emitParseHelper(StringRef kind, StringRef returnType, StringRef builder,
50e768b076SRahul Joshi                        ArrayRef<const Init *> args,
51e768b076SRahul Joshi                        ArrayRef<std::string> argNames, StringRef failure,
52e768b076SRahul Joshi                        mlir::raw_indented_ostream &ios);
5309115580SJacques Pienaar 
5409115580SJacques Pienaar   /// Emits print instructions.
55a5dfcccdSRahul Joshi   void emitPrintHelper(const Record *memberRec, StringRef kind,
56a5dfcccdSRahul Joshi                        StringRef parent, StringRef name,
57a5dfcccdSRahul Joshi                        mlir::raw_indented_ostream &ios);
5809115580SJacques Pienaar 
5909115580SJacques Pienaar   raw_ostream &output;
6009115580SJacques Pienaar };
6109115580SJacques Pienaar } // namespace
6209115580SJacques Pienaar 
6309115580SJacques Pienaar /// Helper to replace set of from strings to target in `s`.
6409115580SJacques Pienaar /// Assumed: non-overlapping replacements.
6509115580SJacques Pienaar static std::string format(StringRef templ,
6609115580SJacques Pienaar                           std::map<std::string, std::string> &&map) {
6709115580SJacques Pienaar   std::string s = templ.str();
6809115580SJacques Pienaar   for (const auto &[from, to] : map)
6909115580SJacques Pienaar     // All replacements start with $, don't treat as anchor.
7009115580SJacques Pienaar     s = std::regex_replace(s, std::regex("\\" + from), to);
7109115580SJacques Pienaar   return s;
7209115580SJacques Pienaar }
7309115580SJacques Pienaar 
7409115580SJacques Pienaar /// Return string with first character capitalized.
7509115580SJacques Pienaar static std::string capitalize(StringRef str) {
7609115580SJacques Pienaar   return ((Twine)toUpper(str[0]) + str.drop_front()).str();
7709115580SJacques Pienaar }
7809115580SJacques Pienaar 
7909115580SJacques Pienaar /// Return the C++ type for the given record.
80a5dfcccdSRahul Joshi static std::string getCType(const Record *def) {
8109115580SJacques Pienaar   std::string format = "{0}";
8209115580SJacques Pienaar   if (def->isSubClassOf("Array")) {
8309115580SJacques Pienaar     def = def->getValueAsDef("elemT");
8409115580SJacques Pienaar     format = "SmallVector<{0}>";
8509115580SJacques Pienaar   }
8609115580SJacques Pienaar 
8709115580SJacques Pienaar   StringRef cType = def->getValueAsString("cType");
8809115580SJacques Pienaar   if (cType.empty()) {
8909115580SJacques Pienaar     if (def->isAnonymous())
9009115580SJacques Pienaar       PrintFatalError(def->getLoc(), "Unable to determine cType");
9109115580SJacques Pienaar 
9209115580SJacques Pienaar     return formatv(format.c_str(), def->getName().str());
9309115580SJacques Pienaar   }
9409115580SJacques Pienaar   return formatv(format.c_str(), cType.str());
9509115580SJacques Pienaar }
9609115580SJacques Pienaar 
97a5dfcccdSRahul Joshi void Generator::emitParseDispatch(StringRef kind,
98a5dfcccdSRahul Joshi                                   ArrayRef<const Record *> vec) {
9909115580SJacques Pienaar   mlir::raw_indented_ostream os(output);
10009115580SJacques Pienaar   char const *head =
10109115580SJacques Pienaar       R"(static {0} read{0}(MLIRContext* context, DialectBytecodeReader &reader))";
10209115580SJacques Pienaar   os << formatv(head, capitalize(kind));
10309115580SJacques Pienaar   auto funScope = os.scope(" {\n", "}\n\n");
10409115580SJacques Pienaar 
105c3c2585bSJacques Pienaar   if (vec.empty()) {
106c3c2585bSJacques Pienaar     os << "return reader.emitError() << \"unknown attribute\", "
107c3c2585bSJacques Pienaar        << capitalize(kind) << "();\n";
108c3c2585bSJacques Pienaar     return;
109c3c2585bSJacques Pienaar   }
110c3c2585bSJacques Pienaar 
11109115580SJacques Pienaar   os << "uint64_t kind;\n";
11209115580SJacques Pienaar   os << "if (failed(reader.readVarInt(kind)))\n"
11309115580SJacques Pienaar      << "  return " << capitalize(kind) << "();\n";
11409115580SJacques Pienaar   os << "switch (kind) ";
11509115580SJacques Pienaar   {
11609115580SJacques Pienaar     auto switchScope = os.scope("{\n", "}\n");
11709115580SJacques Pienaar     for (const auto &it : llvm::enumerate(vec)) {
118a9d003efSJacques Pienaar       if (it.value()->getName() == "ReservedOrDead")
119a9d003efSJacques Pienaar         continue;
120a9d003efSJacques Pienaar 
12109115580SJacques Pienaar       os << formatv("case {1}:\n  return read{0}(context, reader);\n",
12209115580SJacques Pienaar                     it.value()->getName(), it.index());
12309115580SJacques Pienaar     }
12409115580SJacques Pienaar     os << "default:\n"
12509115580SJacques Pienaar        << "  reader.emitError() << \"unknown attribute code: \" "
12609115580SJacques Pienaar        << "<< kind;\n"
12709115580SJacques Pienaar        << "  return " << capitalize(kind) << "();\n";
12809115580SJacques Pienaar   }
12909115580SJacques Pienaar   os << "return " << capitalize(kind) << "();\n";
13009115580SJacques Pienaar }
13109115580SJacques Pienaar 
132a5dfcccdSRahul Joshi void Generator::emitParse(StringRef kind, const Record &x) {
133a9d003efSJacques Pienaar   if (x.getNameInitAsString() == "ReservedOrDead")
134a9d003efSJacques Pienaar     return;
135a9d003efSJacques Pienaar 
13609115580SJacques Pienaar   char const *head =
13709115580SJacques Pienaar       R"(static {0} read{1}(MLIRContext* context, DialectBytecodeReader &reader) )";
13809115580SJacques Pienaar   mlir::raw_indented_ostream os(output);
13909115580SJacques Pienaar   std::string returnType = getCType(&x);
140e768b076SRahul Joshi   os << formatv(head,
141e768b076SRahul Joshi                 kind == "attribute" ? "::mlir::Attribute" : "::mlir::Type",
142e768b076SRahul Joshi                 x.getName());
143e768b076SRahul Joshi   const DagInit *members = x.getValueAsDag("members");
144e768b076SRahul Joshi   SmallVector<std::string> argNames = llvm::to_vector(
145e768b076SRahul Joshi       map_range(members->getArgNames(), [](const StringInit *init) {
14609115580SJacques Pienaar         return init->getAsUnquotedString();
14709115580SJacques Pienaar       }));
1481f8a33c1SJacques Pienaar   StringRef builder = x.getValueAsString("cBuilder").trim();
14909115580SJacques Pienaar   emitParseHelper(kind, returnType, builder, members->getArgs(), argNames,
15009115580SJacques Pienaar                   returnType + "()", os);
15109115580SJacques Pienaar   os << "\n\n";
15209115580SJacques Pienaar }
15309115580SJacques Pienaar 
15409115580SJacques Pienaar void printParseConditional(mlir::raw_indented_ostream &ios,
155e768b076SRahul Joshi                            ArrayRef<const Init *> args,
15609115580SJacques Pienaar                            ArrayRef<std::string> argNames) {
15709115580SJacques Pienaar   ios << "if ";
15809115580SJacques Pienaar   auto parenScope = ios.scope("(", ") {");
15909115580SJacques Pienaar   ios.indent();
16009115580SJacques Pienaar 
16109115580SJacques Pienaar   auto listHelperName = [](StringRef name) {
16209115580SJacques Pienaar     return formatv("read{0}", capitalize(name));
16309115580SJacques Pienaar   };
16409115580SJacques Pienaar 
165*f4d75863SJakub Kuderski   auto parsedArgs = llvm::filter_to_vector(args, [](const Init *const attr) {
166d256b9e8SRahul Joshi     const Record *def = cast<DefInit>(attr)->getDef();
16709115580SJacques Pienaar     if (def->isSubClassOf("Array"))
16809115580SJacques Pienaar       return true;
16909115580SJacques Pienaar     return !def->getValueAsString("cParser").empty();
170*f4d75863SJakub Kuderski   });
17109115580SJacques Pienaar 
17209115580SJacques Pienaar   interleave(
17309115580SJacques Pienaar       zip(parsedArgs, argNames),
174e768b076SRahul Joshi       [&](std::tuple<const Init *&, const std::string &> it) {
175d256b9e8SRahul Joshi         const Record *attr = cast<DefInit>(std::get<0>(it))->getDef();
17609115580SJacques Pienaar         std::string parser;
17709115580SJacques Pienaar         if (auto optParser = attr->getValueAsOptionalString("cParser")) {
17809115580SJacques Pienaar           parser = *optParser;
17909115580SJacques Pienaar         } else if (attr->isSubClassOf("Array")) {
180d256b9e8SRahul Joshi           const Record *def = attr->getValueAsDef("elemT");
18109115580SJacques Pienaar           bool composite = def->isSubClassOf("CompositeBytecode");
18209115580SJacques Pienaar           if (!composite && def->isSubClassOf("AttributeKind"))
18309115580SJacques Pienaar             parser = "succeeded($_reader.readAttributes($_var))";
18409115580SJacques Pienaar           else if (!composite && def->isSubClassOf("TypeKind"))
18509115580SJacques Pienaar             parser = "succeeded($_reader.readTypes($_var))";
18609115580SJacques Pienaar           else
18709115580SJacques Pienaar             parser = ("succeeded($_reader.readList($_var, " +
18809115580SJacques Pienaar                       listHelperName(std::get<1>(it)) + "))")
18909115580SJacques Pienaar                          .str();
19009115580SJacques Pienaar         } else {
19109115580SJacques Pienaar           PrintFatalError(attr->getLoc(), "No parser specified");
19209115580SJacques Pienaar         }
19309115580SJacques Pienaar         std::string type = getCType(attr);
19409115580SJacques Pienaar         ios << format(parser, {{"$_reader", "reader"},
19509115580SJacques Pienaar                                {"$_resultType", type},
19609115580SJacques Pienaar                                {"$_var", std::get<1>(it)}});
19709115580SJacques Pienaar       },
19809115580SJacques Pienaar       [&]() { ios << " &&\n"; });
19909115580SJacques Pienaar }
20009115580SJacques Pienaar 
20109115580SJacques Pienaar void Generator::emitParseHelper(StringRef kind, StringRef returnType,
202e768b076SRahul Joshi                                 StringRef builder, ArrayRef<const Init *> args,
20309115580SJacques Pienaar                                 ArrayRef<std::string> argNames,
20409115580SJacques Pienaar                                 StringRef failure,
20509115580SJacques Pienaar                                 mlir::raw_indented_ostream &ios) {
20609115580SJacques Pienaar   auto funScope = ios.scope("{\n", "}");
20709115580SJacques Pienaar 
20809115580SJacques Pienaar   if (args.empty()) {
20909115580SJacques Pienaar     ios << formatv("return get<{0}>(context);\n", returnType);
21009115580SJacques Pienaar     return;
21109115580SJacques Pienaar   }
21209115580SJacques Pienaar 
21309115580SJacques Pienaar   // Print decls.
21409115580SJacques Pienaar   std::string lastCType = "";
21509115580SJacques Pienaar   for (auto [arg, name] : zip(args, argNames)) {
216e768b076SRahul Joshi     const DefInit *first = dyn_cast<DefInit>(arg);
21709115580SJacques Pienaar     if (!first)
21809115580SJacques Pienaar       PrintFatalError("Unexpected type for " + name);
219d256b9e8SRahul Joshi     const Record *def = first->getDef();
22009115580SJacques Pienaar 
22109115580SJacques Pienaar     // Create variable decls, if there are a block of same type then create
22209115580SJacques Pienaar     // comma separated list of them.
22309115580SJacques Pienaar     std::string cType = getCType(def);
22409115580SJacques Pienaar     if (lastCType == cType) {
22509115580SJacques Pienaar       ios << ", ";
22609115580SJacques Pienaar     } else {
22709115580SJacques Pienaar       if (!lastCType.empty())
22809115580SJacques Pienaar         ios << ";\n";
22909115580SJacques Pienaar       ios << cType << " ";
23009115580SJacques Pienaar     }
23109115580SJacques Pienaar     ios << name;
23209115580SJacques Pienaar     lastCType = cType;
23309115580SJacques Pienaar   }
23409115580SJacques Pienaar   ios << ";\n";
23509115580SJacques Pienaar 
23609115580SJacques Pienaar   // Returns the name of the helper used in list parsing. E.g., the name of the
23709115580SJacques Pienaar   // lambda passed to array parsing.
23809115580SJacques Pienaar   auto listHelperName = [](StringRef name) {
23909115580SJacques Pienaar     return formatv("read{0}", capitalize(name));
24009115580SJacques Pienaar   };
24109115580SJacques Pienaar 
24209115580SJacques Pienaar   // Emit list helper functions.
24309115580SJacques Pienaar   for (auto [arg, name] : zip(args, argNames)) {
244d256b9e8SRahul Joshi     const Record *attr = cast<DefInit>(arg)->getDef();
24509115580SJacques Pienaar     if (!attr->isSubClassOf("Array"))
24609115580SJacques Pienaar       continue;
24709115580SJacques Pienaar 
24809115580SJacques Pienaar     // TODO: Dedupe readers.
249d256b9e8SRahul Joshi     const Record *def = attr->getValueAsDef("elemT");
25009115580SJacques Pienaar     if (!def->isSubClassOf("CompositeBytecode") &&
25109115580SJacques Pienaar         (def->isSubClassOf("AttributeKind") || def->isSubClassOf("TypeKind")))
25209115580SJacques Pienaar       continue;
25309115580SJacques Pienaar 
25409115580SJacques Pienaar     std::string returnType = getCType(def);
25509115580SJacques Pienaar     ios << "auto " << listHelperName(name) << " = [&]() -> FailureOr<"
25609115580SJacques Pienaar         << returnType << "> ";
257e768b076SRahul Joshi     SmallVector<const Init *> args;
25809115580SJacques Pienaar     SmallVector<std::string> argNames;
25909115580SJacques Pienaar     if (def->isSubClassOf("CompositeBytecode")) {
260e768b076SRahul Joshi       const DagInit *members = def->getValueAsDag("members");
26162e2c7fbSRahul Joshi       args = llvm::to_vector(members->getArgs());
26209115580SJacques Pienaar       argNames = llvm::to_vector(
263e768b076SRahul Joshi           map_range(members->getArgNames(), [](const StringInit *init) {
26409115580SJacques Pienaar             return init->getAsUnquotedString();
26509115580SJacques Pienaar           }));
26609115580SJacques Pienaar     } else {
26709115580SJacques Pienaar       args = {def->getDefInit()};
26809115580SJacques Pienaar       argNames = {"temp"};
26909115580SJacques Pienaar     }
27009115580SJacques Pienaar     StringRef builder = def->getValueAsString("cBuilder");
27109115580SJacques Pienaar     emitParseHelper(kind, returnType, builder, args, argNames, "failure()",
27209115580SJacques Pienaar                     ios);
27309115580SJacques Pienaar     ios << ";\n";
27409115580SJacques Pienaar   }
27509115580SJacques Pienaar 
27609115580SJacques Pienaar   // Print parse conditional.
27709115580SJacques Pienaar   printParseConditional(ios, args, argNames);
27809115580SJacques Pienaar 
27909115580SJacques Pienaar   // Compute args to pass to create method.
280*f4d75863SJakub Kuderski   auto passedArgs = llvm::filter_to_vector(
281*f4d75863SJakub Kuderski       argNames, [](StringRef str) { return !str.starts_with("_"); });
28209115580SJacques Pienaar   std::string argStr;
28309115580SJacques Pienaar   raw_string_ostream argStream(argStr);
28409115580SJacques Pienaar   interleaveComma(passedArgs, argStream,
28509115580SJacques Pienaar                   [&](const std::string &str) { argStream << str; });
28609115580SJacques Pienaar   // Return the invoked constructor.
28709115580SJacques Pienaar   ios << "\nreturn "
28809115580SJacques Pienaar       << format(builder, {{"$_resultType", returnType.str()},
28909115580SJacques Pienaar                           {"$_args", argStream.str()}})
29009115580SJacques Pienaar       << ";\n";
29109115580SJacques Pienaar   ios.unindent();
29209115580SJacques Pienaar 
29309115580SJacques Pienaar   // TODO: Emit error in debug.
29409115580SJacques Pienaar   // This assumes the result types in error case can always be empty
29509115580SJacques Pienaar   // constructed.
29609115580SJacques Pienaar   ios << "}\nreturn " << failure << ";\n";
29709115580SJacques Pienaar }
29809115580SJacques Pienaar 
29909115580SJacques Pienaar void Generator::emitPrint(StringRef kind, StringRef type,
300a5dfcccdSRahul Joshi                           ArrayRef<std::pair<int64_t, const Record *>> vec) {
301a9d003efSJacques Pienaar   if (type == "ReservedOrDead")
302a9d003efSJacques Pienaar     return;
303a9d003efSJacques Pienaar 
30409115580SJacques Pienaar   char const *head =
30509115580SJacques Pienaar       R"(static void write({0} {1}, DialectBytecodeWriter &writer) )";
30609115580SJacques Pienaar   mlir::raw_indented_ostream os(output);
30709115580SJacques Pienaar   os << formatv(head, type, kind);
30809115580SJacques Pienaar   auto funScope = os.scope("{\n", "}\n\n");
30909115580SJacques Pienaar 
31009115580SJacques Pienaar   // Check that predicates specified if multiple bytecode instances.
311bccd37f6SRahul Joshi   for (const Record *rec : make_second_range(vec)) {
31209115580SJacques Pienaar     StringRef pred = rec->getValueAsString("printerPredicate");
31309115580SJacques Pienaar     if (vec.size() > 1 && pred.empty()) {
31409115580SJacques Pienaar       for (auto [index, rec] : vec) {
31509115580SJacques Pienaar         (void)index;
31609115580SJacques Pienaar         StringRef pred = rec->getValueAsString("printerPredicate");
31709115580SJacques Pienaar         if (vec.size() > 1 && pred.empty())
31809115580SJacques Pienaar           PrintError(rec->getLoc(),
31909115580SJacques Pienaar                      "Requires parsing predicate given common cType");
32009115580SJacques Pienaar       }
32109115580SJacques Pienaar       PrintFatalError("Unspecified for shared cType " + type);
32209115580SJacques Pienaar     }
32309115580SJacques Pienaar   }
32409115580SJacques Pienaar 
32509115580SJacques Pienaar   for (auto [index, rec] : vec) {
32609115580SJacques Pienaar     StringRef pred = rec->getValueAsString("printerPredicate");
32709115580SJacques Pienaar     if (!pred.empty()) {
32809115580SJacques Pienaar       os << "if (" << format(pred, {{"$_val", kind.str()}}) << ") {\n";
32909115580SJacques Pienaar       os.indent();
33009115580SJacques Pienaar     }
33109115580SJacques Pienaar 
33209115580SJacques Pienaar     os << "writer.writeVarInt(/* " << rec->getName() << " */ " << index
33309115580SJacques Pienaar        << ");\n";
33409115580SJacques Pienaar 
33509115580SJacques Pienaar     auto *members = rec->getValueAsDag("members");
33609115580SJacques Pienaar     for (auto [arg, name] :
33709115580SJacques Pienaar          llvm::zip(members->getArgs(), members->getArgNames())) {
338e768b076SRahul Joshi       const DefInit *def = dyn_cast<DefInit>(arg);
33909115580SJacques Pienaar       assert(def);
340d256b9e8SRahul Joshi       const Record *memberRec = def->getDef();
34109115580SJacques Pienaar       emitPrintHelper(memberRec, kind, kind, name->getAsUnquotedString(), os);
34209115580SJacques Pienaar     }
34309115580SJacques Pienaar 
34409115580SJacques Pienaar     if (!pred.empty()) {
34509115580SJacques Pienaar       os.unindent();
34609115580SJacques Pienaar       os << "}\n";
34709115580SJacques Pienaar     }
34809115580SJacques Pienaar   }
34909115580SJacques Pienaar }
35009115580SJacques Pienaar 
351a5dfcccdSRahul Joshi void Generator::emitPrintHelper(const Record *memberRec, StringRef kind,
35209115580SJacques Pienaar                                 StringRef parent, StringRef name,
35309115580SJacques Pienaar                                 mlir::raw_indented_ostream &ios) {
35409115580SJacques Pienaar   std::string getter;
35509115580SJacques Pienaar   if (auto cGetter = memberRec->getValueAsOptionalString("cGetter");
35609115580SJacques Pienaar       cGetter && !cGetter->empty()) {
35709115580SJacques Pienaar     getter = format(
35809115580SJacques Pienaar         *cGetter,
35909115580SJacques Pienaar         {{"$_attrType", parent.str()},
36009115580SJacques Pienaar          {"$_member", name.str()},
36109115580SJacques Pienaar          {"$_getMember", "get" + convertToCamelFromSnakeCase(name, true)}});
36209115580SJacques Pienaar   } else {
36309115580SJacques Pienaar     getter =
36409115580SJacques Pienaar         formatv("{0}.get{1}()", parent, convertToCamelFromSnakeCase(name, true))
36509115580SJacques Pienaar             .str();
36609115580SJacques Pienaar   }
36709115580SJacques Pienaar 
36809115580SJacques Pienaar   if (memberRec->isSubClassOf("Array")) {
369d256b9e8SRahul Joshi     const Record *def = memberRec->getValueAsDef("elemT");
37009115580SJacques Pienaar     if (!def->isSubClassOf("CompositeBytecode")) {
37109115580SJacques Pienaar       if (def->isSubClassOf("AttributeKind")) {
37209115580SJacques Pienaar         ios << "writer.writeAttributes(" << getter << ");\n";
37309115580SJacques Pienaar         return;
37409115580SJacques Pienaar       }
37509115580SJacques Pienaar       if (def->isSubClassOf("TypeKind")) {
37609115580SJacques Pienaar         ios << "writer.writeTypes(" << getter << ");\n";
37709115580SJacques Pienaar         return;
37809115580SJacques Pienaar       }
37909115580SJacques Pienaar     }
38009115580SJacques Pienaar     std::string returnType = getCType(def);
3811f8a33c1SJacques Pienaar     std::string nestedName = kind.str();
38209115580SJacques Pienaar     ios << "writer.writeList(" << getter << ", [&](" << returnType << " "
3831f8a33c1SJacques Pienaar         << nestedName << ") ";
38409115580SJacques Pienaar     auto lambdaScope = ios.scope("{\n", "});\n");
3851f8a33c1SJacques Pienaar     return emitPrintHelper(def, kind, nestedName, nestedName, ios);
38609115580SJacques Pienaar   }
38709115580SJacques Pienaar   if (memberRec->isSubClassOf("CompositeBytecode")) {
38809115580SJacques Pienaar     auto *members = memberRec->getValueAsDag("members");
38909115580SJacques Pienaar     for (auto [arg, argName] :
39009115580SJacques Pienaar          zip(members->getArgs(), members->getArgNames())) {
391e768b076SRahul Joshi       const DefInit *def = dyn_cast<DefInit>(arg);
39209115580SJacques Pienaar       assert(def);
39309115580SJacques Pienaar       emitPrintHelper(def->getDef(), kind, parent,
39409115580SJacques Pienaar                       argName->getAsUnquotedString(), ios);
39509115580SJacques Pienaar     }
39609115580SJacques Pienaar   }
39709115580SJacques Pienaar 
39809115580SJacques Pienaar   if (std::string printer = memberRec->getValueAsString("cPrinter").str();
39909115580SJacques Pienaar       !printer.empty())
40009115580SJacques Pienaar     ios << format(printer, {{"$_writer", "writer"},
40109115580SJacques Pienaar                             {"$_name", kind.str()},
40209115580SJacques Pienaar                             {"$_getter", getter}})
40309115580SJacques Pienaar         << ";\n";
40409115580SJacques Pienaar }
40509115580SJacques Pienaar 
40609115580SJacques Pienaar void Generator::emitPrintDispatch(StringRef kind, ArrayRef<std::string> vec) {
40709115580SJacques Pienaar   mlir::raw_indented_ostream os(output);
40809115580SJacques Pienaar   char const *head = R"(static LogicalResult write{0}({0} {1},
40909115580SJacques Pienaar                                 DialectBytecodeWriter &writer))";
41009115580SJacques Pienaar   os << formatv(head, capitalize(kind), kind);
41109115580SJacques Pienaar   auto funScope = os.scope(" {\n", "}\n\n");
41209115580SJacques Pienaar 
41309115580SJacques Pienaar   os << "return TypeSwitch<" << capitalize(kind) << ", LogicalResult>(" << kind
41409115580SJacques Pienaar      << ")";
41509115580SJacques Pienaar   auto switchScope = os.scope("", "");
41609115580SJacques Pienaar   for (StringRef type : vec) {
417a9d003efSJacques Pienaar     if (type == "ReservedOrDead")
418a9d003efSJacques Pienaar       continue;
419a9d003efSJacques Pienaar 
42009115580SJacques Pienaar     os << "\n.Case([&](" << type << " t)";
42109115580SJacques Pienaar     auto caseScope = os.scope(" {\n", "})");
42209115580SJacques Pienaar     os << "return write(t, writer), success();\n";
42309115580SJacques Pienaar   }
42409115580SJacques Pienaar   os << "\n.Default([&](" << capitalize(kind) << ") { return failure(); });\n";
42509115580SJacques Pienaar }
42609115580SJacques Pienaar 
42709115580SJacques Pienaar namespace {
42809115580SJacques Pienaar /// Container of Attribute or Type for Dialect.
42909115580SJacques Pienaar struct AttrOrType {
430a5dfcccdSRahul Joshi   std::vector<const Record *> attr, type;
43109115580SJacques Pienaar };
43209115580SJacques Pienaar } // namespace
43309115580SJacques Pienaar 
43409115580SJacques Pienaar static bool emitBCRW(const RecordKeeper &records, raw_ostream &os) {
43509115580SJacques Pienaar   MapVector<StringRef, AttrOrType> dialectAttrOrType;
436b60c6cbcSRahul Joshi   for (const Record *it :
437b60c6cbcSRahul Joshi        records.getAllDerivedDefinitions("DialectAttributes")) {
43809115580SJacques Pienaar     if (!selectedBcDialect.empty() &&
43909115580SJacques Pienaar         it->getValueAsString("dialect") != selectedBcDialect)
44009115580SJacques Pienaar       continue;
44109115580SJacques Pienaar     dialectAttrOrType[it->getValueAsString("dialect")].attr =
442a140931bSRahul Joshi         it->getValueAsListOfDefs("elems");
44309115580SJacques Pienaar   }
444b60c6cbcSRahul Joshi   for (const Record *it : records.getAllDerivedDefinitions("DialectTypes")) {
44509115580SJacques Pienaar     if (!selectedBcDialect.empty() &&
44609115580SJacques Pienaar         it->getValueAsString("dialect") != selectedBcDialect)
44709115580SJacques Pienaar       continue;
44809115580SJacques Pienaar     dialectAttrOrType[it->getValueAsString("dialect")].type =
449a140931bSRahul Joshi         it->getValueAsListOfDefs("elems");
45009115580SJacques Pienaar   }
45109115580SJacques Pienaar 
45209115580SJacques Pienaar   if (dialectAttrOrType.size() != 1)
45309115580SJacques Pienaar     PrintFatalError("Single dialect per invocation required (either only "
45409115580SJacques Pienaar                     "one in input file or specified via dialect option)");
45509115580SJacques Pienaar 
45609115580SJacques Pienaar   auto it = dialectAttrOrType.front();
45709115580SJacques Pienaar   Generator gen(os);
45809115580SJacques Pienaar 
459a5dfcccdSRahul Joshi   SmallVector<std::vector<const Record *> *, 2> vecs;
46009115580SJacques Pienaar   SmallVector<std::string, 2> kinds;
46109115580SJacques Pienaar   vecs.push_back(&it.second.attr);
46209115580SJacques Pienaar   kinds.push_back("attribute");
46309115580SJacques Pienaar   vecs.push_back(&it.second.type);
46409115580SJacques Pienaar   kinds.push_back("type");
46509115580SJacques Pienaar   for (auto [vec, kind] : zip(vecs, kinds)) {
46609115580SJacques Pienaar     // Handle Attribute/Type emission.
467a5dfcccdSRahul Joshi     std::map<std::string, std::vector<std::pair<int64_t, const Record *>>>
468a5dfcccdSRahul Joshi         perType;
46909115580SJacques Pienaar     for (auto kt : llvm::enumerate(*vec))
47009115580SJacques Pienaar       perType[getCType(kt.value())].emplace_back(kt.index(), kt.value());
47109115580SJacques Pienaar     for (const auto &jt : perType) {
47209115580SJacques Pienaar       for (auto kt : jt.second)
47309115580SJacques Pienaar         gen.emitParse(kind, *std::get<1>(kt));
47409115580SJacques Pienaar       gen.emitPrint(kind, jt.first, jt.second);
47509115580SJacques Pienaar     }
47609115580SJacques Pienaar     gen.emitParseDispatch(kind, *vec);
47709115580SJacques Pienaar 
47809115580SJacques Pienaar     SmallVector<std::string> types;
47909115580SJacques Pienaar     for (const auto &it : perType) {
48009115580SJacques Pienaar       types.push_back(it.first);
48109115580SJacques Pienaar     }
48209115580SJacques Pienaar     gen.emitPrintDispatch(kind, types);
48309115580SJacques Pienaar   }
48409115580SJacques Pienaar 
48509115580SJacques Pienaar   return false;
48609115580SJacques Pienaar }
48709115580SJacques Pienaar 
48809115580SJacques Pienaar static mlir::GenRegistration
48909115580SJacques Pienaar     genBCRW("gen-bytecode", "Generate dialect bytecode readers/writers",
49009115580SJacques Pienaar             [](const RecordKeeper &records, raw_ostream &os) {
49109115580SJacques Pienaar               return emitBCRW(records, os);
49209115580SJacques Pienaar             });
493