From 41d0d2c18e5d2ffb024ed2c5bd1e3eb07310eab8 Mon Sep 17 00:00:00 2001 From: Google JSIR Bot Date: Mon, 6 Jul 2026 06:06:21 -0700 Subject: [PATCH] No public description PiperOrigin-RevId: 943238905 --- maldoca/astgen/ast_def.cc | 18 ++++ maldoca/astgen/ast_def.h | 42 +++++++++ maldoca/astgen/ast_def.proto | 34 +++++++ maldoca/astgen/ast_gen_main.cc | 75 +++++++++++---- maldoca/astgen/ast_to_ir_source_printer.cc | 101 +++++++++++++++----- maldoca/astgen/ast_to_ir_source_printer.h | 20 +++- maldoca/astgen/ir_to_ast_source_printer.cc | 105 ++++++++++++++++----- maldoca/astgen/ir_to_ast_source_printer.h | 20 +++- maldoca/astgen/type.cc | 25 +++-- maldoca/astgen/type.h | 37 +++++--- maldoca/astgen/type_test.cc | 7 +- 11 files changed, 390 insertions(+), 94 deletions(-) diff --git a/maldoca/astgen/ast_def.cc b/maldoca/astgen/ast_def.cc index 6debce8..2ee7a9e 100644 --- a/maldoca/astgen/ast_def.cc +++ b/maldoca/astgen/ast_def.cc @@ -360,6 +360,24 @@ absl::StatusOr AstDef::FromProto(const AstDefPb& pb) { for (auto kind : union_type_pb.kinds()) { union_type_node->kinds_.push_back(static_cast(kind)); } + if (union_type_pb.has_ir_op_name()) { + union_type_node->ir_op_name_ = union_type_pb.ir_op_name(); + } + if (union_type_pb.has_should_generate_dispatch()) { + union_type_node->should_generate_dispatch_ = + union_type_pb.should_generate_dispatch(); + } + for (const auto& o : union_type_pb.dispatch_overrides()) { + std::optional ir_op_name; + if (o.has_ir_op_name()) { + ir_op_name = o.ir_op_name(); + } + union_type_node->dispatch_overrides_.emplace( + o.type(), NodeDef::DispatchOverride{o.visitor(), ir_op_name}); + } + for (const auto& s : union_type_pb.dispatch_skip()) { + union_type_node->dispatch_skip_.insert(s); + } if (nodes.contains(union_type_pb.name())) { return absl::InvalidArgumentError( absl::StrCat(union_type_pb.name(), " already exists!")); diff --git a/maldoca/astgen/ast_def.h b/maldoca/astgen/ast_def.h index c8be037..4a661ea 100644 --- a/maldoca/astgen/ast_def.h +++ b/maldoca/astgen/ast_def.h @@ -22,6 +22,7 @@ #include #include "absl/container/flat_hash_map.h" +#include "absl/container/flat_hash_set.h" #include "absl/log/log.h" #include "absl/status/statusor.h" #include "absl/strings/string_view.h" @@ -175,6 +176,44 @@ class NodeDef { // If false, the op is expected to be manually written. bool should_generate_ir_op() const { return should_generate_ir_op_; } + // Whether IR dispatch code should be automatically generated for unions. + bool should_generate_dispatch() const { return should_generate_dispatch_; } + + // Overrides for generated dispatch code. + // + // For a union type (e.g., `Expression`), the generator automatically + // produces dispatch code (e.g., `dynamic_cast` chain in AST-to-IR, or + // `TypeSwitch` in IR-to-AST) to route to the correct visitor for each member + // (e.g., `VisitIdentifier`). + // + // `DispatchOverride` allows customizing this routing for specific members. + struct DispatchOverride { + // The name of the visitor function to call. + // E.g., "VisitIdentifierRef" instead of the default "VisitIdentifier". + std::string visitor; + + // The IR op name to use for this member. + // E.g., "jsir.IdentifierRef" instead of "jsir.Identifier". + std::optional ir_op_name; + }; + + // Map from union member type name (e.g., "Identifier") to its dispatch + // override. + const absl::flat_hash_map& dispatch_overrides() + const { + return dispatch_overrides_; + } + + // Set of union member type names to skip in the generated dispatch code. + // + // If a member is skipped, it will not be included in the generated + // dispatch methods, and must be handled manually if needed. + // + // E.g., {"InvalidExpression"} to skip generating dispatch for invalid nodes. + const absl::flat_hash_set& dispatch_skip() const { + return dispatch_skip_; + } + // The allowed FieldKinds for this node. Does not include those specified in // ancestors. // @@ -293,6 +332,9 @@ class NodeDef { std::vector aggregated_kinds_; bool has_control_flow_; std::optional ir_op_name_; + bool should_generate_dispatch_ = true; + absl::flat_hash_map dispatch_overrides_; + absl::flat_hash_set dispatch_skip_; bool has_fold_; std::vector additional_mlir_traits_; std::vector aggregated_additional_mlir_traits_; diff --git a/maldoca/astgen/ast_def.proto b/maldoca/astgen/ast_def.proto index c607113..7a994b7 100644 --- a/maldoca/astgen/ast_def.proto +++ b/maldoca/astgen/ast_def.proto @@ -342,6 +342,40 @@ message UnionTypePb { // Supported kinds. Each kind leads to a different IR op. repeated FieldKind kinds = 5; + + // [Optional] Custom MLIR op name. + optional string ir_op_name = 6; + + // If true, automatically generate the corresponding IR dispatch code. + optional bool should_generate_dispatch = 7 [default = true]; + + message DispatchOverridePb { + // The name of the union member type to override. + // E.g., "Identifier". + optional string type = 1; + + // The name of the visitor function to call. + // E.g., "VisitIdentifierRef" instead of the default "VisitIdentifier". + optional string visitor = 2; + + // The IR op name to use for this member. + // E.g., "jsir.IdentifierRef" instead of "jsir.Identifier". + optional string ir_op_name = 3; + } + + // Overrides for generated dispatch code. + // + // Allows customizing the generated visitor and IR op name for specific + // union members. + repeated DispatchOverridePb dispatch_overrides = 8; + + // Set of union member type names to skip in the generated dispatch code. + // + // If a member is skipped, it will not be included in the generated + // dispatch methods, and must be handled manually if needed. + // + // E.g., "InvalidExpression" to skip generating dispatch for invalid nodes. + repeated string dispatch_skip = 9; } // Top-level AST definition. diff --git a/maldoca/astgen/ast_gen_main.cc b/maldoca/astgen/ast_gen_main.cc index 895816d..2002699 100644 --- a/maldoca/astgen/ast_gen_main.cc +++ b/maldoca/astgen/ast_gen_main.cc @@ -50,6 +50,31 @@ ABSL_FLAG(std::string, ast_path, "", "The directory for the AST code in C++."); ABSL_FLAG(std::string, ir_path, "", "The directory for the IR code in TableGen and C++."); +// Flags to support mapping AST nodes to a different target IR dialect +// (e.g. mapping SWC's "jsswc" AST to the standard "jsir" dialect). +ABSL_FLAG(std::string, ir_lang_name, "", + "The language name for the IR (e.g. 'js')."); + +// Overrides to prevent generated files from overwriting other dialect +// conversions and to use custom names/paths. +ABSL_FLAG(std::string, ast_to_ir_cc_path, "", + "Override output path for generated AST to IR C++ source."); + +ABSL_FLAG(std::string, ir_to_ast_cc_path, "", + "Override output path for generated IR to AST C++ source."); + +ABSL_FLAG(std::string, ast_to_ir_header_include_path, "", + "Override include path for AST to IR header in generated source."); + +ABSL_FLAG(std::string, ir_to_ast_header_include_path, "", + "Override include path for IR to AST header in generated source."); + +ABSL_FLAG(std::string, ast_to_ir_class_name, "", + "Override class name for AST to IR converter."); + +ABSL_FLAG(std::string, ir_to_ast_class_name, "", + "Override class name for IR to AST converter."); + namespace maldoca { namespace { @@ -58,6 +83,15 @@ absl::Status AstGenMain() { auto cc_namespace = absl::GetFlag(FLAGS_cc_namespace); auto ast_path = absl::GetFlag(FLAGS_ast_path); auto ir_path = absl::GetFlag(FLAGS_ir_path); + auto ir_lang_name = absl::GetFlag(FLAGS_ir_lang_name); + auto ast_to_ir_cc_path_flag = absl::GetFlag(FLAGS_ast_to_ir_cc_path); + auto ir_to_ast_cc_path_flag = absl::GetFlag(FLAGS_ir_to_ast_cc_path); + auto ast_to_ir_header_include_path = + absl::GetFlag(FLAGS_ast_to_ir_header_include_path); + auto ir_to_ast_header_include_path = + absl::GetFlag(FLAGS_ir_to_ast_header_include_path); + auto ast_to_ir_class_name = absl::GetFlag(FLAGS_ast_to_ir_class_name); + auto ir_to_ast_class_name = absl::GetFlag(FLAGS_ir_to_ast_class_name); AstDefPb ast_def_pb; ABSL_RETURN_IF_ERROR(ParseTextProtoFile(ast_def_path, &ast_def_pb)); @@ -85,25 +119,34 @@ absl::Status AstGenMain() { ABSL_RETURN_IF_ERROR(SetFileContents(ast_from_json_path, ast_from_json)); if (!ir_path.empty()) { - std::string ir_tablegen = PrintIrTableGen(ast_def, ir_path); - auto ir_tablegen_path = JoinPath( - ir_path, absl::StrCat(ast_def.lang_name(), "ir_ops.generated.td")); - std::cout << "Writing ir_tablegen to " << ir_tablegen_path << "\n"; - ABSL_RETURN_IF_ERROR(SetFileContents(ir_tablegen_path, ir_tablegen)); - - std::string ast_to_ir = - PrintAstToIrSource(ast_def, cc_namespace, ast_path, ir_path); - auto ast_to_ir_path = JoinPath( - ir_path, "conversion", - absl::StrCat("ast_to_", ast_def.lang_name(), "ir.generated.cc")); + if (ir_lang_name.empty() || ir_lang_name == ast_def.lang_name()) { + std::string ir_tablegen = PrintIrTableGen(ast_def, ir_path); + auto ir_tablegen_path = JoinPath( + ir_path, absl::StrCat(ast_def.lang_name(), "ir_ops.generated.td")); + std::cout << "Writing ir_tablegen to " << ir_tablegen_path << "\n"; + ABSL_RETURN_IF_ERROR(SetFileContents(ir_tablegen_path, ir_tablegen)); + } + + std::string ast_to_ir = PrintAstToIrSource( + ast_def, cc_namespace, ast_path, ir_path, ir_lang_name, + ast_to_ir_header_include_path, ast_to_ir_class_name); + auto ast_to_ir_path = + ast_to_ir_cc_path_flag.empty() + ? JoinPath(ir_path, "conversion", + absl::StrCat("ast_to_", ast_def.lang_name(), + "ir.generated.cc")) + : ast_to_ir_cc_path_flag; std::cout << "Writing ast_to_ir to " << ast_to_ir_path << "\n"; ABSL_RETURN_IF_ERROR(SetFileContents(ast_to_ir_path, ast_to_ir)); - std::string ir_to_ast = - PrintIrToAstSource(ast_def, cc_namespace, ast_path, ir_path); - auto ir_to_ast_path = JoinPath( - ir_path, "conversion", - absl::StrCat(ast_def.lang_name(), "ir_to_ast.generated.cc")); + std::string ir_to_ast = PrintIrToAstSource( + ast_def, cc_namespace, ast_path, ir_path, ir_lang_name, + ir_to_ast_header_include_path, ir_to_ast_class_name); + auto ir_to_ast_path = ir_to_ast_cc_path_flag.empty() + ? JoinPath(ir_path, "conversion", + absl::StrCat(ast_def.lang_name(), + "ir_to_ast.generated.cc")) + : ir_to_ast_cc_path_flag; std::cout << "Writing ir_to_ast to " << ir_to_ast_path << "\n"; ABSL_RETURN_IF_ERROR(SetFileContents(ir_to_ast_path, ir_to_ast)); } diff --git a/maldoca/astgen/ast_to_ir_source_printer.cc b/maldoca/astgen/ast_to_ir_source_printer.cc index 29af652..75b3603 100644 --- a/maldoca/astgen/ast_to_ir_source_printer.cc +++ b/maldoca/astgen/ast_to_ir_source_printer.cc @@ -60,8 +60,9 @@ static Symbol GetVisitor(const NodeDef& node, FieldKind kind) { // Gets the name of the *RegionEndOp. // - For an lval or rval (expression): ExprRegionEndOp. // - For a list of lvals or rvals (expressions): ExprsRegionEndOp. -Symbol GetRegionEndOp(const AstDef& ast, const FieldDef& field) { - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); +Symbol GetRegionEndOp(const AstDef& ast, const FieldDef& field, + absl::string_view ir_lang) { + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); Symbol region_end_op; switch (field.kind()) { @@ -102,8 +103,15 @@ void AstToIrSourcePrinter::PrintAst(const AstDef& ast, Println("// clang-format off"); Println(); - PrintIncludeHeader( - absl::StrCat(ir_path, "/conversion/ast_to_", ast.lang_name(), "ir.h")); + if (!header_include_path_.empty()) { + PrintIncludeHeader(header_include_path_); + } else { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + PrintIncludeHeader( + absl::StrCat(ir_path, "/conversion/ast_to_", ir_lang, "ir.h")); + } Println(); Println("#include "); @@ -135,7 +143,7 @@ void AstToIrSourcePrinter::PrintAst(const AstDef& ast, Println(); for (const auto* node : ast.topological_sorted_nodes()) { - if (!node->children().empty()) { + if (!node->children().empty() && node->should_generate_dispatch()) { for (FieldKind kind : node->aggregated_kinds()) { PrintNonLeafNode(ast, *node, kind); } @@ -161,7 +169,10 @@ void AstToIrSourcePrinter::PrintAst(const AstDef& ast, void AstToIrSourcePrinter::PrintNonLeafNode(const AstDef& ast, const NodeDef& node, FieldKind kind) { - auto ir_op_name = node.ir_op_name(ast.lang_name(), kind); + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + auto ir_op_name = node.ir_op_name(ir_lang, kind); std::string return_type; if (ir_op_name.has_value()) { return_type = ir_op_name.value().ToPascalCase(); @@ -184,26 +195,40 @@ void AstToIrSourcePrinter::PrintNonLeafNode(const AstDef& ast, } } } - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); auto visitor = GetVisitor(node, kind); + std::string class_name = class_name_.empty() + ? absl::StrCat("AstTo", ir_name.ToPascalCase()) + : class_name_; auto vars = WithVars({ {"Ret", return_type}, {"Name", (Symbol(ast.lang_name()) + node.name()).ToPascalCase()}, - {"IrName", ir_name.ToPascalCase()}, + {"ClassName", class_name}, {"Visitor", visitor.ToPascalCase()}, }); Println( - "$Ret$ AstTo$IrName$::$Visitor$(mlir::OpBuilder &builder, const $Name$ " + "$Ret$ $ClassName$::$Visitor$(mlir::OpBuilder &builder, const $Name$ " "*node) {"); { auto indent = WithIndent(); for (const NodeDef* leaf : node.leaves()) { + if (node.dispatch_skip().contains(leaf->name())) { + continue; + } + auto it = node.dispatch_overrides().find(leaf->name()); + std::string visitor_name; + if (it != node.dispatch_overrides().end() && + !it->second.visitor.empty()) { + visitor_name = it->second.visitor; + } else { + visitor_name = GetVisitor(*leaf, kind).ToPascalCase(); + } auto vars = WithVars({ {"LeafName", (Symbol(ast.lang_name()) + leaf->name()).ToPascalCase()}, {"leaf_name", Symbol(leaf->name()).ToCcVarName()}, - {"LeafVisitor", GetVisitor(*leaf, kind).ToPascalCase()}, + {"LeafVisitor", visitor_name}, }); Println( "if (auto *$leaf_name$ = dynamic_cast(node)) {"); @@ -219,8 +244,11 @@ void AstToIrSourcePrinter::PrintNonLeafNode(const AstDef& ast, void AstToIrSourcePrinter::PrintLeafNode(const AstDef& ast, const NodeDef& node, FieldKind kind) { - auto ir_op_name = node.ir_op_name(ast.lang_name(), kind).value(); - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + auto ir_op_name = node.ir_op_name(ir_lang, kind).value(); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); auto visitor = Symbol("Visit") + node.name(); if (kind == FIELD_KIND_LVAL) { @@ -241,16 +269,20 @@ void AstToIrSourcePrinter::PrintLeafNode(const AstDef& ast, const NodeDef& node, break; } + std::string class_name = class_name_.empty() + ? absl::StrCat("AstTo", ir_name.ToPascalCase()) + : class_name_; + auto vars = WithVars({ {"OpName", ir_op_name.ToPascalCase()}, {"Name", (Symbol(ast.lang_name()) + node.name()).ToPascalCase()}, - {"IrName", ir_name.ToPascalCase()}, + {"ClassName", class_name}, {"Visitor", visitor.ToPascalCase()}, {"Creator", creator.ToPascalCase()}, }); Println( - "$OpName$ AstTo$IrName$::$Visitor$(mlir::OpBuilder &builder, const " + "$OpName$ $ClassName$::$Visitor$(mlir::OpBuilder &builder, const " "$Name$ *node) {"); { auto indent = WithIndent(); @@ -320,7 +352,10 @@ void AstToIrSourcePrinter::PrintRegion(const AstDef& ast, const NodeDef& node, auto lhs = Symbol("mlir") + field.name(); auto lhs_region = lhs + "region"; auto rhs = absl::StrCat("node->", field.name().ToCcVarName(), "()"); - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); auto vars = WithVars({ {"lhs", lhs.ToCcVarName()}, @@ -351,7 +386,7 @@ void AstToIrSourcePrinter::PrintRegion(const AstDef& ast, const NodeDef& node, } }(); - Symbol region_end_op = GetRegionEndOp(ast, field); + Symbol region_end_op = GetRegionEndOp(ast, field, ir_lang); PrintToIr(ast, action, field.type(), RefOrVal::kRef, field.kind(), lhs, rhs); @@ -397,8 +432,11 @@ void AstToIrSourcePrinter::PrintBuiltinToIr(const AstDef& ast, Action action, const BuiltinType& type, const Symbol& lhs, const std::string& rhs) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); auto vars = WithVars({ - {"mlir_type", type.CcMlirBuilderType(FIELD_KIND_ATTR)}, + {"mlir_type", type.CcMlirBuilderType(ir_lang, FIELD_KIND_ATTR)}, {"lhs", lhs.ToCcVarName()}, {"rhs", rhs}, }); @@ -440,6 +478,9 @@ void AstToIrSourcePrinter::PrintClassToIr(const AstDef& ast, Action action, const ClassType& type, FieldKind kind, const Symbol& lhs, const std::string& rhs) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); auto vars = WithVars({ {"ClassName", type.name().ToPascalCase()}, {"lhs", lhs.ToCcVarName()}, @@ -449,7 +490,7 @@ void AstToIrSourcePrinter::PrintClassToIr(const AstDef& ast, Action action, switch (action) { case Action::kDef: { auto vars = WithVars({ - {"cc_mlir_type", type.CcMlirBuilderType(kind)}, + {"cc_mlir_type", type.CcMlirBuilderType(ir_lang, kind)}, }); Print("$cc_mlir_type$ "); ABSL_FALLTHROUGH_INTENDED; @@ -508,6 +549,9 @@ void AstToIrSourcePrinter::PrintVariantToIr(const AstDef& ast, Action action, RefOrVal ref_or_val, FieldKind kind, const Symbol& lhs, const std::string& rhs) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); auto vars = WithVars({ {"lhs", lhs.ToCcVarName()}, {"rhs", rhs}, @@ -517,7 +561,7 @@ void AstToIrSourcePrinter::PrintVariantToIr(const AstDef& ast, Action action, switch (action) { case Action::kDef: { auto vars = WithVars({ - {"cc_mlir_type", type.CcMlirBuilderType(kind)}, + {"cc_mlir_type", type.CcMlirBuilderType(ir_lang, kind)}, }); Println("$cc_mlir_type$ $lhs$;"); case_action = Action::kAssign; @@ -562,6 +606,9 @@ void AstToIrSourcePrinter::PrintListToIr(const AstDef& ast, Action action, const ListType& type, FieldKind kind, const Symbol& lhs, const std::string& rhs) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); const auto lhs_element = Symbol("mlir_element"); const auto rhs_element = "element"; @@ -667,8 +714,7 @@ void AstToIrSourcePrinter::PrintListToIr(const AstDef& ast, Action action, Println("} else {"); { auto indent = WithIndent(); - auto none_op = - Symbol(absl::StrCat(ast.lang_name(), "ir")) + "NoneOp"; + auto none_op = Symbol(absl::StrCat(ir_lang, "ir")) + "NoneOp"; auto vars = WithVars({ {"NoneOp", none_op.ToPascalCase()}, }); @@ -730,6 +776,9 @@ void AstToIrSourcePrinter::PrintNullableToIr(const AstDef& ast, Action action, RefOrVal ref_or_val, FieldKind kind, const Symbol& lhs, const std::string& rhs) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); auto vars = WithVars({ {"lhs", lhs.ToCcVarName()}, {"rhs", rhs}, @@ -747,7 +796,7 @@ void AstToIrSourcePrinter::PrintNullableToIr(const AstDef& ast, Action action, break; case Action::kDef: { auto vars = WithVars({ - {"mlir_type", type.CcMlirBuilderType(kind)}, + {"mlir_type", type.CcMlirBuilderType(ir_lang, kind)}, }); Println("$mlir_type$ $lhs$;"); non_null_action = Action::kAssign; @@ -774,11 +823,15 @@ void AstToIrSourcePrinter::PrintNullableToIr(const AstDef& ast, Action action, std::string PrintAstToIrSource(const AstDef& ast, absl::string_view cc_namespace, absl::string_view ast_path, - absl::string_view ir_path) { + absl::string_view ir_path, + absl::string_view ir_lang_name, + absl::string_view header_include_path, + absl::string_view class_name) { std::string str; { google::protobuf::io::StringOutputStream os(&str); - AstToIrSourcePrinter printer(&os); + AstToIrSourcePrinter printer(&os, ir_lang_name, header_include_path, + class_name); printer.PrintAst(ast, cc_namespace, ast_path, ir_path); } diff --git a/maldoca/astgen/ast_to_ir_source_printer.h b/maldoca/astgen/ast_to_ir_source_printer.h index d7ef817..1492d79 100644 --- a/maldoca/astgen/ast_to_ir_source_printer.h +++ b/maldoca/astgen/ast_to_ir_source_printer.h @@ -28,8 +28,14 @@ namespace maldoca { class AstToIrSourcePrinter : public CcPrinterBase { public: - explicit AstToIrSourcePrinter(google::protobuf::io::ZeroCopyOutputStream* os) - : CcPrinterBase(os) {} + explicit AstToIrSourcePrinter(google::protobuf::io::ZeroCopyOutputStream* os, + absl::string_view ir_lang_name = "", + absl::string_view header_include_path = "", + absl::string_view class_name = "") + : CcPrinterBase(os), + ir_lang_name_(ir_lang_name), + header_include_path_(header_include_path), + class_name_(class_name) {} // Action: What to do with the converted IR value/attribute. // @@ -169,6 +175,11 @@ class AstToIrSourcePrinter : public CcPrinterBase { // }); void PrintRegion(const AstDef& ast, const NodeDef& node, const FieldDef& field); + + private: + std::string ir_lang_name_; + std::string header_include_path_; + std::string class_name_; }; // Prints the "ast_toir.generated.cc" file. @@ -194,7 +205,10 @@ class AstToIrSourcePrinter : public CcPrinterBase { std::string PrintAstToIrSource(const AstDef& ast, absl::string_view cc_namespace, absl::string_view ast_path, - absl::string_view ir_path); + absl::string_view ir_path, + absl::string_view ir_lang_name = "", + absl::string_view header_include_path = "", + absl::string_view class_name = ""); } // namespace maldoca diff --git a/maldoca/astgen/ir_to_ast_source_printer.cc b/maldoca/astgen/ir_to_ast_source_printer.cc index 28e5221..6c6cc00 100644 --- a/maldoca/astgen/ir_to_ast_source_printer.cc +++ b/maldoca/astgen/ir_to_ast_source_printer.cc @@ -74,8 +74,15 @@ void IrToAstSourcePrinter::PrintAst(const AstDef& ast, Println("// clang-format off"); Println(); - PrintIncludeHeader( - absl::StrCat(ir_path, "/conversion/", ast.lang_name(), "ir_to_ast.h")); + if (!header_include_path_.empty()) { + PrintIncludeHeader(header_include_path_); + } else { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + PrintIncludeHeader( + absl::StrCat(ir_path, "/conversion/", ir_lang, "ir_to_ast.h")); + } Println(); Println("#include "); @@ -117,7 +124,7 @@ void IrToAstSourcePrinter::PrintAst(const AstDef& ast, Println(); for (const auto* node : ast.topological_sorted_nodes()) { - if (!node->children().empty()) { + if (!node->children().empty() && node->should_generate_dispatch()) { for (FieldKind kind : node->aggregated_kinds()) { PrintNonLeafNode(ast, *node, kind); } @@ -143,7 +150,10 @@ void IrToAstSourcePrinter::PrintAst(const AstDef& ast, void IrToAstSourcePrinter::PrintNonLeafNode(const AstDef& ast, const NodeDef& node, FieldKind kind) { - auto ir_op_name = node.ir_op_name(ast.lang_name(), kind); + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + auto ir_op_name = node.ir_op_name(ir_lang, kind); std::string input_type; if (ir_op_name.has_value()) { input_type = ir_op_name->ToPascalCase(); @@ -161,8 +171,11 @@ void IrToAstSourcePrinter::PrintNonLeafNode(const AstDef& ast, break; } } - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); auto visitor = GetVisitor(node, kind); + std::string class_name = class_name_.empty() + ? absl::StrCat(ir_name.ToPascalCase(), "ToAst") + : class_name_; auto vars = WithVars({ {"InputType", input_type}, @@ -170,12 +183,12 @@ void IrToAstSourcePrinter::PrintNonLeafNode(const AstDef& ast, kind == FIELD_KIND_ATTR ? "mlir::Attribute" : "mlir::Operation*"}, {"Name", (Symbol(ast.lang_name()) + node.name()).ToPascalCase()}, {"name", kind == FIELD_KIND_ATTR ? "attr" : "op"}, - {"IrName", ir_name.ToPascalCase()}, + {"ClassName", class_name}, {"Visitor", visitor.ToPascalCase()}, }); Println("absl::StatusOr>"); - Println("$IrName$ToAst::$Visitor$($InputType$ $name$) {"); + Println("$ClassName$::$Visitor$($InputType$ $name$) {"); { auto indent = WithIndent(); Println("using Ret = absl::StatusOr>;"); @@ -183,10 +196,34 @@ void IrToAstSourcePrinter::PrintNonLeafNode(const AstDef& ast, { auto indent = WithIndent(); for (const NodeDef* leaf : node.leaves()) { + if (node.dispatch_skip().contains(leaf->name())) { + continue; + } + std::string visitor_name; + std::string op_name; + auto it = node.dispatch_overrides().find(leaf->name()); + + if (it != node.dispatch_overrides().end() && + !it->second.visitor.empty()) { + visitor_name = it->second.visitor; + } else { + visitor_name = GetVisitor(*leaf, kind).ToPascalCase(); + } + + if (it != node.dispatch_overrides().end() && + it->second.ir_op_name.has_value()) { + op_name = *it->second.ir_op_name; + } else { + auto ir_op = leaf->ir_op_name(ir_lang, kind); + if (!ir_op.has_value()) { + LOG(FATAL) << "Leaf node " << leaf->name() + << " has no IR op name for " << ir_lang; + } + op_name = ir_op->ToPascalCase(); + } auto vars = WithVars({ - {"LeafOpName", - leaf->ir_op_name(ast.lang_name(), kind)->ToPascalCase()}, - {"LeafVisitor", GetVisitor(*leaf, kind).ToPascalCase()}, + {"LeafOpName", op_name}, + {"LeafVisitor", visitor_name}, }); Println(".Case([&]($LeafOpName$ $name$) {"); Println(" return $LeafVisitor$($name$);"); @@ -204,24 +241,31 @@ void IrToAstSourcePrinter::PrintNonLeafNode(const AstDef& ast, void IrToAstSourcePrinter::PrintLeafNode(const AstDef& ast, const NodeDef& node, FieldKind kind) { - auto ir_op_name = node.ir_op_name(ast.lang_name(), kind).value(); - auto ir_name = Symbol(absl::StrCat(ast.lang_name(), "ir")); + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); + auto ir_op_name = node.ir_op_name(ir_lang, kind).value(); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); auto visitor = Symbol("Visit") + node.name(); if (kind == FIELD_KIND_LVAL) { visitor += "Ref"; } + std::string class_name = class_name_.empty() + ? absl::StrCat(ir_name.ToPascalCase(), "ToAst") + : class_name_; + auto vars = WithVars({ {"OpName", ir_op_name.ToPascalCase()}, {"Name", (Symbol(ast.lang_name()) + node.name()).ToPascalCase()}, {"name", kind == FIELD_KIND_ATTR ? "attr" : "op"}, - {"IrName", ir_name.ToPascalCase()}, + {"ClassName", class_name}, {"Visitor", visitor.ToPascalCase()}, }); Println("absl::StatusOr>"); - Println("$IrName$ToAst::$Visitor$($OpName$ $name$) {"); + Println("$ClassName$::$Visitor$($OpName$ $name$) {"); { auto indent = WithIndent(); for (const auto* field : node.aggregated_fields()) { @@ -304,6 +348,9 @@ void IrToAstSourcePrinter::PrintField(const AstDef& ast, const NodeDef& node, void IrToAstSourcePrinter::PrintRegion(const AstDef& ast, const NodeDef& node, const FieldDef& field) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); MaybeNull maybe_null = OptionalnessToMaybeNull(field.optionalness()); std::string converter_type = [&]() -> std::string { @@ -315,13 +362,15 @@ void IrToAstSourcePrinter::PrintRegion(const AstDef& ast, const NodeDef& node, case FIELD_KIND_RVAL: case FIELD_KIND_LVAL: { if (field.type().IsA()) { - auto end_op = - Symbol(absl::StrCat(ast.lang_name(), "ir")) + "ExprsRegionEndOp"; - return absl::StrCat("ExprsRegion<", end_op.ToPascalCase(), ">"); + std::string end_op = + absl::StrCat(Symbol(absl::StrCat(ir_lang, "ir")).ToPascalCase(), + "ExprsRegionEndOp"); + return absl::StrCat("ExprsRegion<", end_op, ">"); } else { - auto end_op = - Symbol(absl::StrCat(ast.lang_name(), "ir")) + "ExprRegionEndOp"; - return absl::StrCat("ExprRegion<", end_op.ToPascalCase(), ">"); + std::string end_op = + absl::StrCat(Symbol(absl::StrCat(ir_lang, "ir")).ToPascalCase(), + "ExprRegionEndOp"); + return absl::StrCat("ExprRegion<", end_op, ">"); } } case FIELD_KIND_STMT: { @@ -387,10 +436,14 @@ void IrToAstSourcePrinter::PrintConverter(const AstDef& ast, const Type& type, absl::string_view lang_name, FieldKind kind, MaybeNull maybe_null) { + absl::string_view ir_lang = ir_lang_name_.empty() + ? ast.lang_name() + : absl::string_view(ir_lang_name_); if (maybe_null == MaybeNull::kYes) { if (kind == FIELD_KIND_LVAL || kind == FIELD_KIND_RVAL) { - auto none_op = Symbol(absl::StrCat(ast.lang_name(), "ir")) + "NoneOp"; - Print(absl::StrCat("Nullable<", none_op.ToPascalCase(), ">(\n")); + std::string none_op = absl::StrCat( + Symbol(absl::StrCat(ir_lang, "ir")).ToPascalCase(), "NoneOp"); + Print(absl::StrCat("Nullable<", none_op, ">(\n")); } else { Print("Nullable(\n"); } @@ -526,11 +579,15 @@ void IrToAstSourcePrinter::PrintListConverter(const AstDef& ast, std::string PrintIrToAstSource(const AstDef& ast, absl::string_view cc_namespace, absl::string_view ast_path, - absl::string_view ir_path) { + absl::string_view ir_path, + absl::string_view ir_lang_name, + absl::string_view header_include_path, + absl::string_view class_name) { std::string str; { google::protobuf::io::StringOutputStream os(&str); - IrToAstSourcePrinter printer(&os); + IrToAstSourcePrinter printer(&os, ir_lang_name, header_include_path, + class_name); printer.PrintAst(ast, cc_namespace, ast_path, ir_path); } diff --git a/maldoca/astgen/ir_to_ast_source_printer.h b/maldoca/astgen/ir_to_ast_source_printer.h index 528177d..0d4c2a9 100644 --- a/maldoca/astgen/ir_to_ast_source_printer.h +++ b/maldoca/astgen/ir_to_ast_source_printer.h @@ -27,8 +27,14 @@ namespace maldoca { class IrToAstSourcePrinter : public CcPrinterBase { public: - explicit IrToAstSourcePrinter(google::protobuf::io::ZeroCopyOutputStream* os) - : CcPrinterBase(os) {} + explicit IrToAstSourcePrinter(google::protobuf::io::ZeroCopyOutputStream* os, + absl::string_view ir_lang_name = "", + absl::string_view header_include_path = "", + absl::string_view class_name = "") + : CcPrinterBase(os), + ir_lang_name_(ir_lang_name), + header_include_path_(header_include_path), + class_name_(class_name) {} void PrintAst(const AstDef& ast, absl::string_view cc_namespace, absl::string_view ast_path, absl::string_view ir_path); @@ -61,12 +67,20 @@ class IrToAstSourcePrinter : public CcPrinterBase { void PrintListConverter(const AstDef& ast, const ListType& list_type, absl::string_view lang_name, FieldKind kind); + + private: + std::string ir_lang_name_; + std::string header_include_path_; + std::string class_name_; }; std::string PrintIrToAstSource(const AstDef& ast, absl::string_view cc_namespace, absl::string_view ast_path, - absl::string_view ir_path); + absl::string_view ir_path, + absl::string_view ir_lang_name = "", + absl::string_view header_include_path = "", + absl::string_view class_name = ""); } // namespace maldoca diff --git a/maldoca/astgen/type.cc b/maldoca/astgen/type.cc index 5a8c498..62f7c44 100644 --- a/maldoca/astgen/type.cc +++ b/maldoca/astgen/type.cc @@ -389,7 +389,8 @@ std::string ClassType::CcGetterType(CcGetterKind getter_kind) const { // CcMlirBuilderType() / CcMlirGetterType() // ============================================================================= -std::string ListType::CcMlirBuilderType(FieldKind kind) const { +std::string ListType::CcMlirBuilderType(absl::string_view ir_lang_name, + FieldKind kind) const { switch (kind) { case FIELD_KIND_UNSPECIFIED: LOG(FATAL) << "Unspecified FieldKind."; @@ -403,7 +404,8 @@ std::string ListType::CcMlirBuilderType(FieldKind kind) const { } } -std::string ListType::CcMlirGetterType(FieldKind kind) const { +std::string ListType::CcMlirGetterType(absl::string_view ir_lang_name, + FieldKind kind) const { switch (kind) { case FIELD_KIND_UNSPECIFIED: LOG(FATAL) << "Unspecified FieldKind."; @@ -417,10 +419,11 @@ std::string ListType::CcMlirGetterType(FieldKind kind) const { } } -std::string VariantType::CcMlirType(FieldKind kind) const { +std::string VariantType::CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const { absl::flat_hash_set cc_mlir_types; for (const auto& type : types()) { - cc_mlir_types.insert(type->CcMlirType(kind)); + cc_mlir_types.insert(type->CcMlirType(ir_lang_name, kind)); } switch (kind) { @@ -442,7 +445,8 @@ std::string VariantType::CcMlirType(FieldKind kind) const { } } -std::string BuiltinType::CcMlirType(FieldKind kind) const { +std::string BuiltinType::CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const { switch (kind) { case FIELD_KIND_UNSPECIFIED: LOG(FATAL) << "Unspecified FieldKind."; @@ -466,7 +470,8 @@ std::string BuiltinType::CcMlirType(FieldKind kind) const { } } -std::string EnumType::CcMlirType(FieldKind kind) const { +std::string EnumType::CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const { switch (kind) { case FIELD_KIND_UNSPECIFIED: LOG(FATAL) << "Unspecified FieldKind."; @@ -481,19 +486,21 @@ std::string EnumType::CcMlirType(FieldKind kind) const { return "mlir::StringAttr"; } -std::string ClassType::CcMlirType(FieldKind kind) const { +std::string ClassType::CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const { + absl::string_view ir_lang = ir_lang_name.empty() ? lang_name_ : ir_lang_name; switch (kind) { case FIELD_KIND_UNSPECIFIED: LOG(FATAL) << "Unspecified FieldKind."; case FIELD_KIND_ATTR: { if (node_def_ != nullptr) { - auto ir_op_name = node_def_->ir_op_name(lang_name_, kind); + auto ir_op_name = node_def_->ir_op_name(ir_lang, kind); if (ir_op_name.has_value()) { return ir_op_name->ToPascalCase(); } } - auto ir_name = Symbol(absl::StrCat(lang_name_, "ir")); + auto ir_name = Symbol(absl::StrCat(ir_lang, "ir")); return (ir_name + name() + "Attr").ToPascalCase(); } case FIELD_KIND_LVAL: diff --git a/maldoca/astgen/type.h b/maldoca/astgen/type.h index 21c31a0..8487238 100644 --- a/maldoca/astgen/type.h +++ b/maldoca/astgen/type.h @@ -254,7 +254,8 @@ class Type { // // [Builtin] // => mlir::ArrayAttr - virtual std::string CcMlirBuilderType(FieldKind kind) const = 0; + virtual std::string CcMlirBuilderType(absl::string_view ir_lang_name, + FieldKind kind) const = 0; // Prints the C++ type for MLIR getters. // @@ -302,7 +303,8 @@ class Type { // // [Builtin] // => mlir::ArrayAttr - virtual std::string CcMlirGetterType(FieldKind kind) const = 0; + virtual std::string CcMlirGetterType(absl::string_view ir_lang_name, + FieldKind kind) const = 0; // Prints the MLIR TableGen type. // @@ -370,14 +372,17 @@ class NonListType : public Type { // For `NonListType`, `CcMlirGetterType` and `CcMlirBuilderType` are the same. // For the definitions of `CcMlirGetterType` and `CcMlirBuilderType`, see // comments for class `Type`. - virtual std::string CcMlirType(FieldKind kind) const = 0; + virtual std::string CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const = 0; - std::string CcMlirBuilderType(FieldKind kind) const final { - return CcMlirType(kind); + std::string CcMlirBuilderType(absl::string_view ir_lang_name, + FieldKind kind) const final { + return CcMlirType(ir_lang_name, kind); } - std::string CcMlirGetterType(FieldKind kind) const final { - return CcMlirType(kind); + std::string CcMlirGetterType(absl::string_view ir_lang_name, + FieldKind kind) const final { + return CcMlirType(ir_lang_name, kind); } protected: @@ -415,9 +420,11 @@ class ListType : public Type { std::string CcGetterType(CcGetterKind getter_kind) const override; - std::string CcMlirBuilderType(FieldKind kind) const override; + std::string CcMlirBuilderType(absl::string_view ir_lang_name, + FieldKind kind) const override; - std::string CcMlirGetterType(FieldKind kind) const override; + std::string CcMlirGetterType(absl::string_view ir_lang_name, + FieldKind kind) const override; std::string TdType(FieldKind kind) const override; @@ -467,7 +474,8 @@ class VariantType : public NonListType { std::string CcGetterType(CcGetterKind getter_kind) const override; - std::string CcMlirType(FieldKind kind) const final; + std::string CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const final; std::string TdType(FieldKind kind) const override; @@ -501,7 +509,8 @@ class BuiltinType : public ScalarType { std::string CcGetterType(CcGetterKind getter_kind) const override; - std::string CcMlirType(FieldKind kind) const final; + std::string CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const final; std::string TdType(FieldKind kind) const override; @@ -527,7 +536,8 @@ class EnumType : public ScalarType { std::string CcGetterType(CcGetterKind getter_kind) const override; - std::string CcMlirType(FieldKind kind) const final; + std::string CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const final; std::string TdType(FieldKind kind) const override; @@ -561,7 +571,8 @@ class ClassType : public ScalarType { std::string CcGetterType(CcGetterKind getter_kind) const override; - std::string CcMlirType(FieldKind kind) const final; + std::string CcMlirType(absl::string_view ir_lang_name, + FieldKind kind) const final; std::string TdType(FieldKind kind) const override; diff --git a/maldoca/astgen/type_test.cc b/maldoca/astgen/type_test.cc index 0ba13ae..dc5a5bd 100644 --- a/maldoca/astgen/type_test.cc +++ b/maldoca/astgen/type_test.cc @@ -65,6 +65,8 @@ void TestTypePbToTypeAndPrint(TypeTestCase type_test_case) { EXPECT_EQ(type->TdType(field_kind), td_type); } + absl::string_view ir_lang = + type_test_case.cc_lang_name != nullptr ? type_test_case.cc_lang_name : ""; for (const auto &pair : type_test_case.cc_mlir_builder_type) { // We don't allow C++17 in the codebase for compatibility reasons, so we // cannot use structured binding. @@ -72,7 +74,8 @@ void TestTypePbToTypeAndPrint(TypeTestCase type_test_case) { std::string cc_mlir_builder_type; std::tie(field_kind, cc_mlir_builder_type) = pair; - EXPECT_EQ(type->CcMlirBuilderType(field_kind), cc_mlir_builder_type); + EXPECT_EQ(type->CcMlirBuilderType(ir_lang, field_kind), + cc_mlir_builder_type); } for (const auto &pair : type_test_case.cc_mlir_getter_type) { // We don't allow C++17 in the codebase for compatibility reasons, so we @@ -82,7 +85,7 @@ void TestTypePbToTypeAndPrint(TypeTestCase type_test_case) { // std::tie(field_kind, cc_mlir_getter_type) = pair; auto [field_kind, cc_mlir_getter_type] = pair; - EXPECT_EQ(type->CcMlirGetterType(field_kind), cc_mlir_getter_type); + EXPECT_EQ(type->CcMlirGetterType(ir_lang, field_kind), cc_mlir_getter_type); } }