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