[Mlir-commits] [mlir] [MLIR][tblgen] generate EnumAttr C bindings (PR #186633)

Maksim Levental llvmlistbot at llvm.org
Sat Mar 14 18:02:45 PDT 2026


https://github.com/makslevental created https://github.com/llvm/llvm-project/pull/186633

None

>From 5bb05153adfb213e8049000a56fb145b5856e1f1 Mon Sep 17 00:00:00 2001
From: makslevental <maksim.levental at gmail.com>
Date: Tue, 16 Dec 2025 19:41:23 -0800
Subject: [PATCH 1/4] [MLIR][TblGen] add AttrOrTypeCAPIGen

---
 mlir/cmake/modules/AddMLIR.cmake             |   3 +
 mlir/include/mlir/IR/EnumAttr.td             |   1 +
 mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp | 373 +++++++++++++++++++
 mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp  |  42 +--
 mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.h |  44 +++
 mlir/tools/mlir-tblgen/CMakeLists.txt        |   1 +
 6 files changed, 425 insertions(+), 39 deletions(-)
 create mode 100644 mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp

diff --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake
index 60b73876d53fe..fa28fa035d986 100644
--- a/mlir/cmake/modules/AddMLIR.cmake
+++ b/mlir/cmake/modules/AddMLIR.cmake
@@ -171,6 +171,9 @@ function(add_mlir_dialect dialect dialect_namespace)
   mlir_tablegen(${dialect}.h.inc -gen-op-decls)
   mlir_tablegen(${dialect}.cpp.inc -gen-op-defs)
   mlir_tablegen(${dialect}Types.h.inc -gen-typedef-decls -typedefs-dialect=${dialect_namespace})
+  mlir_tablegen(${dialect}CAPIEnumAttrs.h.inc -gen-enum-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
+  mlir_tablegen(${dialect}CAPIAttrs.h.inc -gen-attrdef-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
+  mlir_tablegen(${dialect}CAPITypes.h.inc -gen-typedef-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}Types.cpp.inc -gen-typedef-defs -typedefs-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}Dialect.h.inc -gen-dialect-decls -dialect=${dialect_namespace})
   mlir_tablegen(${dialect}Dialect.cpp.inc -gen-dialect-defs -dialect=${dialect_namespace})
diff --git a/mlir/include/mlir/IR/EnumAttr.td b/mlir/include/mlir/IR/EnumAttr.td
index cfa2ac89350a1..3a3d85348f0f1 100644
--- a/mlir/include/mlir/IR/EnumAttr.td
+++ b/mlir/include/mlir/IR/EnumAttr.td
@@ -499,6 +499,7 @@ class EnumParameter<EnumInfo enumInfo>
     !cast<EnumAttrInfo>(enumInfo).parameterParser, ?);
   let printer = !if(!isa<EnumAttrInfo>(enumInfo),
     !cast<EnumAttrInfo>(enumInfo).parameterPrinter, ?);
+  string underlyingEnumName = enumInfo.className;
 }
 
 // An attribute backed by a C++ enum. The attribute contains a single
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
new file mode 100644
index 0000000000000..5e5f4f29d44aa
--- /dev/null
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
@@ -0,0 +1,373 @@
+//===- AttrOrTypeCAPIGen.cpp - MLIR Attribute and Type CAPI generation ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "AttrOrTypeFormatGen.h"
+#include "CppGenUtilities.h"
+#include "mlir/TableGen/AttrOrTypeDef.h"
+#include "mlir/TableGen/Class.h"
+#include "mlir/TableGen/EnumInfo.h"
+#include "mlir/TableGen/GenInfo.h"
+#include "mlir/TableGen/Interfaces.h"
+#include "mlir/TableGen/Pass.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/TableGen/Error.h"
+#include "llvm/TableGen/Record.h"
+#include "llvm/TableGen/TableGenBackend.h"
+
+#define DEBUG_TYPE "mlir-tblgen-attr-or-type-capi-gen"
+
+using namespace mlir;
+using namespace mlir::tblgen;
+using llvm::formatv;
+using llvm::Record;
+using llvm::RecordKeeper;
+
+static llvm::cl::OptionCategory attrOrTypeCAPIDefGenCat(
+    "Options for -gen-attr-capi-* and -gen-typedef-capi-*");
+static llvm::cl::opt<std::string>
+    capiDialect("attr-or-type-capi-dialect",
+                llvm::cl::desc("Generate C APIs for this dialect"),
+                llvm::cl::cat(attrOrTypeCAPIDefGenCat),
+                llvm::cl::CommaSeparated);
+static llvm::cl::opt<std::string> capiNamespacePrefix(
+    "attr-or-type-capi-namespace-prefix",
+    llvm::cl::desc("Generate C APIs with this namespace prefix"),
+    llvm::cl::cat(attrOrTypeCAPIDefGenCat));
+
+static std::string makeIdentifier(StringRef str) {
+  if (!str.empty() && llvm::isDigit(static_cast<unsigned char>(str.front()))) {
+    std::string newStr = std::string("_") + str.str();
+    return newStr;
+  }
+  return str.str();
+}
+
+static std::string withCapitalFirstLetter(std::string name) {
+  name[0] = static_cast<std::string::value_type>(
+      std::toupper(static_cast<unsigned char>(name[0])));
+  return name;
+}
+
+static std::string namespacePrefix() {
+  static const std::string prefix = [] {
+    if (!capiNamespacePrefix.empty())
+      return capiNamespacePrefix.getValue();
+    return withCapitalFirstLetter(capiDialect.getValue());
+  }();
+  return prefix;
+}
+
+static void emitAttrTypeHeader(StringRef name, raw_ostream &os) {
+  const char *const header = R"(
+//===----------------------------------------------------------------------===//
+// {0}
+//===----------------------------------------------------------------------===//
+
+)";
+  os << formatv(header, name);
+}
+
+namespace {
+struct CAPIDefGenerator : DefGenerator {
+  CAPIDefGenerator(ArrayRef<const llvm::Record *> defs, raw_ostream &os,
+                   const StringRef &defType, const StringRef &valueType,
+                   bool isAttrGenerator)
+      : DefGenerator(defs, os, defType, valueType, isAttrGenerator) {}
+
+  bool emitDecls(StringRef selectedDialect) override;
+};
+} // namespace
+
+static bool isUnsupportedParam(const AttrOrTypeParameter &param) {
+  if (auto *defInit = dyn_cast<llvm::DefInit>(param.getDef())) {
+    const Record *rec = defInit->getDef();
+    if (rec->isSubClassOf("ArrayRefParameter"))
+      return true;
+    if (rec->isSubClassOf("OptionalArrayRefParameter"))
+      return true;
+  }
+  return false;
+}
+
+static std::string mapParamTypeToCAPI(const AttrOrTypeParameter &param) {
+  StringRef cppType = param.getCppType();
+  if (const llvm::DefInit *defInit = dyn_cast<llvm::DefInit>(param.getDef())) {
+    const Record *rec = defInit->getDef();
+    if (rec->isSubClassOf("EnumParameter")) {
+      std::string type = "mlir";
+      type += namespacePrefix();
+      type += rec->getValueAsString("underlyingEnumName");
+      return type;
+    }
+    if (rec->isSubClassOf("StringRefParameter"))
+      return "MlirStringRef";
+  }
+  if (cppType == "Type")
+    return "MlirType";
+  if (cppType == "Attribute" || cppType == "::mlir::DictionaryAttr" ||
+      cppType == "::mlir::ArrayAttr" || cppType == "DictionaryAttr" ||
+      cppType == "ArrayAttr")
+    return "MlirAttribute";
+  return cppType.str();
+}
+
+static SmallVector<MethodParameter>
+getGettorParams(ArrayRef<AttrOrTypeParameter> params,
+                std::initializer_list<MethodParameter> prefix) {
+  SmallVector<MethodParameter> builderParams;
+  builderParams.append(prefix.begin(), prefix.end());
+  for (auto &param : params) {
+    builderParams.emplace_back(mapParamTypeToCAPI(param), param.getName());
+  }
+  return builderParams;
+}
+
+static void emitGettorDecl(StringRef name, ArrayRef<AttrOrTypeParameter> params,
+                           raw_ostream &os, bool isAttrGenerator) {
+  os << "MLIR_CAPI_EXPORTED ";
+  if (isAttrGenerator)
+    os << "MlirAttribute ";
+  else
+    os << "MlirType ";
+  os << "mlir" + namespacePrefix() << name << "Get(";
+  SmallVector<MethodParameter> params_ =
+      getGettorParams(params, {{"MlirContext", "context"}});
+  for (auto [i, param] : llvm::enumerate(params_)) {
+    os << param.getType() << " " << param.getName()
+       << (i < params_.size() - 1 ? ", " : "");
+  }
+  os << ");\n";
+}
+
+static void emitAccessorDecls(StringRef name,
+                              ArrayRef<AttrOrTypeParameter> params,
+                              raw_ostream &os, bool isAttrGenerator) {
+  for (AttrOrTypeParameter param : params) {
+    if (isUnsupportedParam(param))
+      continue;
+    std::string paramName = param.getName().str();
+    os << "MLIR_CAPI_EXPORTED ";
+    os << mapParamTypeToCAPI(param) << " mlir" << namespacePrefix() << name
+       << "Get" << withCapitalFirstLetter(param.getName().str());
+    if (isAttrGenerator)
+      os << "(MlirAttribute attr);";
+    else
+      os << "(MlirType type);";
+    os << "\n";
+  }
+}
+
+static void emitTypeIDDecl(StringRef name, raw_ostream &os) {
+  os << "MLIR_CAPI_EXPORTED MlirTypeID mlir" << namespacePrefix() << name
+     << "GetTypeID();\n";
+}
+
+static void emitIsADecl(StringRef name, raw_ostream &os, bool isAttrGenerator) {
+  os << "MLIR_CAPI_EXPORTED bool mlir";
+  if (isAttrGenerator)
+    os << "Attribute";
+  else
+    os << "Type";
+  os << "IsA" << namespacePrefix() << name;
+  if (isAttrGenerator)
+    os << "(MlirAttribute attr);";
+  else
+    os << "(MlirType type);";
+  os << "\n";
+}
+
+static bool emitEnumDecls(ArrayRef<const Record *> records, raw_ostream &os) {
+  {
+    llvm::IfDefEmitter scope(os, "GET_ENUM_CAPI_DECLS");
+    for (const auto *rec : records) {
+      EnumInfo enumInfo(*rec);
+      os << "#define GET_" + enumInfo.getEnumClassName().upper() +
+                "_ENUM_CAPI_DECL\n";
+    }
+  }
+
+  for (const auto *rec : records) {
+    EnumInfo enumInfo(*rec);
+    llvm::IfDefEmitter scope(os, "GET_" + enumInfo.getEnumClassName().upper() +
+                                     "_ENUM_CAPI_DECL");
+    os << "// " << enumInfo.getSummary() << "\n";
+    os << "enum mlir" << namespacePrefix() << enumInfo.getEnumClassName();
+
+    if (!enumInfo.getUnderlyingType().empty())
+      os << " : " << enumInfo.getUnderlyingType();
+    os << " {\n";
+
+    for (const EnumCase &enumerant : enumInfo.getAllCases()) {
+      auto symbol = makeIdentifier(enumerant.getSymbol());
+      auto value = enumerant.getValue();
+      if (value >= 0)
+        os << formatv("  {0} = {1},\n", symbol, value);
+      else
+        os << formatv("  {0},\n", symbol);
+    }
+    os << "};\n";
+  }
+
+  os << "\n";
+
+  return false;
+}
+
+static bool emitEnumAttrDecls(ArrayRef<const Record *> records, raw_ostream &os,
+                              StringRef selectedDialect) {
+  {
+    llvm::IfDefEmitter scope(os, "GET_ENUM_ATTR_CAPI_DECLS");
+    for (const auto *rec : records) {
+      AttrOrTypeDef attr(&*rec);
+      StringRef dialect = attr.getDialect().getName();
+      if (dialect != selectedDialect)
+        continue;
+      EnumInfo enumInfo(*attr.getDef()->getValueAsDef("enum"));
+      StringRef name = enumInfo.getEnumClassName();
+      os << "#define GET_" + namespacePrefix() + "_" + name.upper() +
+                "_ENUM_ATTR_CAPI_DECL\n";
+    }
+  }
+
+  for (const Record *rec : records) {
+    AttrOrTypeDef attr(&*rec);
+    StringRef dialect = attr.getDialect().getName();
+    if (dialect != selectedDialect)
+      continue;
+
+    EnumInfo enumInfo(*attr.getDef()->getValueAsDef("enum"));
+    llvm::IfDefEmitter scope(os, "GET_" + namespacePrefix() + "_" +
+                                     enumInfo.getEnumClassName().upper() +
+                                     "_ENUM_ATTR_CAPI_DECL");
+
+    os << "MLIR_CAPI_EXPORTED MlirAttribute mlir" << namespacePrefix()
+       << enumInfo.getEnumClassName() << "AttrGet(MlirContext context, mlir"
+       << namespacePrefix() << enumInfo.getEnumClassName() << " value);\n";
+
+    std::string name = enumInfo.getEnumClassName().str() + "Attr";
+    emitTypeIDDecl(name, os);
+    emitIsADecl(name, os, /*isAttrGenerator*/ true);
+
+    os << "MLIR_CAPI_EXPORTED mlir" << namespacePrefix()
+       << enumInfo.getEnumClassName() << " mlir";
+    os << namespacePrefix() << name << "GetValue(MlirAttribute attr);\n";
+  }
+
+  os << "\n";
+
+  return false;
+}
+
+bool CAPIDefGenerator::emitDecls(StringRef selectedDialect) {
+  emitSourceFileHeader((defType + "Def C API Def Declarations").str(), os);
+
+  SmallVector<AttrOrTypeDef, 16> defs;
+  collectAllDefs(selectedDialect, defRecords, defs);
+  if (defs.empty())
+    return false;
+
+  {
+    llvm::IfDefEmitter scope(os, "GET_" + defType.upper() + "_CAPI_DECLS");
+    for (const AttrOrTypeDef &def : defs) {
+      StringRef name = def.getCppClassName();
+      os << "#define GET_" + name.upper() + "_" + defType.upper() +
+                "_CAPI_DECL\n";
+    }
+  }
+
+  for (const AttrOrTypeDef &def : defs) {
+    StringRef name = def.getCppClassName();
+    llvm::IfDefEmitter scope(os, "GET_" + name.upper() + "_" + defType.upper() +
+                                     "_CAPI_DECL");
+
+    ArrayRef<AttrOrTypeParameter> params = def.getParameters();
+    emitAttrTypeHeader(name, os);
+    if (!llvm::any_of(params, isUnsupportedParam))
+      emitGettorDecl(name, params, os, isAttrGenerator);
+    emitTypeIDDecl(name, os);
+    emitIsADecl(name, os, isAttrGenerator);
+    if (def.genAccessors() && !params.empty())
+      emitAccessorDecls(name, params, os, isAttrGenerator);
+  }
+
+  os << "\n";
+
+  return false;
+}
+
+namespace {
+/// A specialized generator for AttrDefs.
+struct CAPIAttrDefGenerator : public CAPIDefGenerator {
+  CAPIAttrDefGenerator(ArrayRef<const llvm::Record *> defs, raw_ostream &os)
+      : CAPIDefGenerator(defs, os, "Attr", "Attribute",
+                         /*isAttrGenerator=*/true) {}
+};
+/// A specialized generator for TypeDefs.
+struct CAPITypeDefGenerator : public CAPIDefGenerator {
+  CAPITypeDefGenerator(ArrayRef<const llvm::Record *> defs, raw_ostream &os)
+      : CAPIDefGenerator(defs, os, "Type", "Type",
+                         /*isAttrGenerator=*/false) {}
+};
+} // namespace
+
+//===----------------------------------------------------------------------===//
+// GEN: Registration hooks
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// AttrDef
+//===----------------------------------------------------------------------===//
+
+static mlir::GenRegistration genEnumDecls(
+    "gen-enum-capi-decls", "Generate Enum C API declarations",
+    [](const RecordKeeper &records, raw_ostream &os) {
+      emitSourceFileHeader("Enum C API Declarations", os);
+      emitEnumDecls(records.getAllDerivedDefinitionsIfDefined("EnumInfo"), os);
+      emitEnumAttrDecls(records.getAllDerivedDefinitionsIfDefined("EnumAttr"),
+                        os, capiDialect);
+      return false;
+    });
+
+static mlir::GenRegistration genAttrDecls(
+    "gen-attrdef-capi-decls", "Generate AttrDef C API declarations",
+    [](const RecordKeeper &records, raw_ostream &os) {
+      CAPIAttrDefGenerator generator(
+          records.getAllDerivedDefinitionsIfDefined("AttrDef"), os);
+      return generator.emitDecls(capiDialect);
+    });
+
+// static mlir::GenRegistration
+//     genAttrDefs("gen-attrdef-capi-defs", "Generate AttrDef C API
+//     definitions",
+//                 [](const RecordKeeper &records, raw_ostream &os) {
+//                   CAPIAttrDefGenerator generator(records, os);
+//                   return generator.emitDefs(attrDialect);
+//                 });
+
+//===----------------------------------------------------------------------===//
+// TypeDef
+//===----------------------------------------------------------------------===//
+
+static mlir::GenRegistration genTypeDecls(
+    "gen-typedef-capi-decls", "Generate TypeDef C API declarations",
+    [](const RecordKeeper &records, raw_ostream &os) {
+      CAPITypeDefGenerator generator(
+          records.getAllDerivedDefinitionsIfDefined("TypeDef"), os);
+      return generator.emitDecls(capiDialect);
+    });
+
+// static mlir::GenRegistration
+//     genTypeDefs("gen-typedef-capi-defs", "Generate TypeDef C API
+//     definitions",
+//                 [](const RecordKeeper &records, raw_ostream &os) {
+//                   CAPITypeDefGenerator generator(records, os);
+//                   return generator.emitDefs(capiDialect);
+//                 });
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
index 64f35e7fef6d3..5394e82520ae0 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeDefGen.cpp
@@ -33,9 +33,9 @@ using llvm::RecordKeeper;
 
 /// Find all the AttrOrTypeDef for the specified dialect. If no dialect
 /// specified and can only find one dialect's defs, use that.
-static void collectAllDefs(StringRef selectedDialect,
-                           ArrayRef<const Record *> records,
-                           SmallVectorImpl<AttrOrTypeDef> &resultDefs) {
+void mlir::tblgen::collectAllDefs(StringRef selectedDialect,
+                                  ArrayRef<const Record *> records,
+                                  SmallVectorImpl<AttrOrTypeDef> &resultDefs) {
   // Nothing to do if no defs were found.
   if (records.empty())
     return;
@@ -829,42 +829,6 @@ void DefGen::emitStorageClass() {
 //===----------------------------------------------------------------------===//
 
 namespace {
-/// This struct is the base generator used when processing tablegen interfaces.
-class DefGenerator {
-public:
-  bool emitDecls(StringRef selectedDialect);
-  bool emitDefs(StringRef selectedDialect);
-
-protected:
-  DefGenerator(ArrayRef<const Record *> defs, raw_ostream &os,
-               StringRef defType, StringRef valueType, bool isAttrGenerator)
-      : defRecords(defs), os(os), defType(defType), valueType(valueType),
-        isAttrGenerator(isAttrGenerator) {
-    // Sort by occurrence in file.
-    llvm::sort(defRecords, [](const Record *lhs, const Record *rhs) {
-      return lhs->getID() < rhs->getID();
-    });
-  }
-
-  /// Emit the list of def type names.
-  void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs);
-  /// Emit the code to dispatch between different defs during parsing/printing.
-  void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs);
-
-  /// The set of def records to emit.
-  std::vector<const Record *> defRecords;
-  /// The attribute or type class to emit.
-  /// The stream to emit to.
-  raw_ostream &os;
-  /// The prefix of the tablegen def name, e.g. Attr or Type.
-  StringRef defType;
-  /// The C++ base value type of the def, e.g. Attribute or Type.
-  StringRef valueType;
-  /// Flag indicating if this generator is for Attributes. False if the
-  /// generator is for types.
-  bool isAttrGenerator;
-};
-
 /// A specialized generator for AttrDefs.
 struct AttrDefGenerator : public DefGenerator {
   AttrDefGenerator(const RecordKeeper &records, raw_ostream &os)
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.h b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.h
index d4711532a79bb..ca20fdba5ba96 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.h
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeFormatGen.h
@@ -20,6 +20,50 @@ class AttrOrTypeDef;
 void generateAttrOrTypeFormat(const AttrOrTypeDef &def, MethodBody &parser,
                               MethodBody &printer);
 
+/// Find all the AttrOrTypeDef for the specified dialect. If no dialect
+/// specified and can only find one dialect's defs, use that.
+void collectAllDefs(StringRef selectedDialect,
+                    ArrayRef<const llvm::Record *> records,
+                    SmallVectorImpl<AttrOrTypeDef> &resultDefs);
+
+/// This struct is the base generator used when processing tablegen interfaces.
+class DefGenerator {
+public:
+  virtual ~DefGenerator() = default;
+  virtual bool emitDecls(StringRef selectedDialect);
+  virtual bool emitDefs(StringRef selectedDialect);
+
+protected:
+  DefGenerator(ArrayRef<const llvm::Record *> defs, raw_ostream &os,
+               StringRef defType, StringRef valueType, bool isAttrGenerator)
+      : defRecords(defs), os(os), defType(defType), valueType(valueType),
+        isAttrGenerator(isAttrGenerator) {
+    // Sort by occurrence in file.
+    llvm::sort(defRecords,
+               [](const llvm::Record *lhs, const llvm::Record *rhs) {
+                 return lhs->getID() < rhs->getID();
+               });
+  }
+
+  /// Emit the list of def type names.
+  void emitTypeDefList(ArrayRef<AttrOrTypeDef> defs);
+  /// Emit the code to dispatch between different defs during parsing/printing.
+  void emitParsePrintDispatch(ArrayRef<AttrOrTypeDef> defs);
+
+  /// The set of def records to emit.
+  std::vector<const llvm::Record *> defRecords;
+  /// The attribute or type class to emit.
+  /// The stream to emit to.
+  raw_ostream &os;
+  /// The prefix of the tablegen def name, e.g. Attr or Type.
+  StringRef defType;
+  /// The C++ base value type of the def, e.g. Attribute or Type.
+  StringRef valueType;
+  /// Flag indicating if this generator is for Attributes. False if the
+  /// generator is for types.
+  bool isAttrGenerator;
+};
+
 } // namespace tblgen
 } // namespace mlir
 
diff --git a/mlir/tools/mlir-tblgen/CMakeLists.txt b/mlir/tools/mlir-tblgen/CMakeLists.txt
index d7087cba3c874..4256613ce4848 100644
--- a/mlir/tools/mlir-tblgen/CMakeLists.txt
+++ b/mlir/tools/mlir-tblgen/CMakeLists.txt
@@ -8,6 +8,7 @@ set(LLVM_LINK_COMPONENTS
 add_tablegen(mlir-tblgen MLIR
   DESTINATION "${MLIR_TOOLS_INSTALL_DIR}"
   EXPORT MLIR
+  AttrOrTypeCAPIGen.cpp
   AttrOrTypeDefGen.cpp
   AttrOrTypeFormatGen.cpp
   BytecodeDialectGen.cpp

>From e7ed0eba4f710b851393bae548f8366577a88b21 Mon Sep 17 00:00:00 2001
From: jgreenbaum <j.greenbaum at computer.org>
Date: Fri, 6 Mar 2026 16:06:26 -0800
Subject: [PATCH 2/4] Working with Index dialect

---
 mlir/cmake/modules/AddMLIR.cmake             |   1 +
 mlir/include/mlir-c/Dialect/Index.h          |   9 ++
 mlir/lib/CAPI/Dialect/Index.cpp              |   6 +
 mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp | 159 +++++++++++++++----
 4 files changed, 147 insertions(+), 28 deletions(-)

diff --git a/mlir/cmake/modules/AddMLIR.cmake b/mlir/cmake/modules/AddMLIR.cmake
index fa28fa035d986..12b07801b38d5 100644
--- a/mlir/cmake/modules/AddMLIR.cmake
+++ b/mlir/cmake/modules/AddMLIR.cmake
@@ -173,6 +173,7 @@ function(add_mlir_dialect dialect dialect_namespace)
   mlir_tablegen(${dialect}Types.h.inc -gen-typedef-decls -typedefs-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}CAPIEnumAttrs.h.inc -gen-enum-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}CAPIAttrs.h.inc -gen-attrdef-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
+  mlir_tablegen(${dialect}CAPIAttrs.cpp.inc -gen-attrdef-capi-defs -attr-or-type-capi-dialect=${dialect_namespace})  
   mlir_tablegen(${dialect}CAPITypes.h.inc -gen-typedef-capi-decls -attr-or-type-capi-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}Types.cpp.inc -gen-typedef-defs -typedefs-dialect=${dialect_namespace})
   mlir_tablegen(${dialect}Dialect.h.inc -gen-dialect-decls -dialect=${dialect_namespace})
diff --git a/mlir/include/mlir-c/Dialect/Index.h b/mlir/include/mlir-c/Dialect/Index.h
index 3f05694acf7a7..df377240f6cf9 100644
--- a/mlir/include/mlir-c/Dialect/Index.h
+++ b/mlir/include/mlir-c/Dialect/Index.h
@@ -17,6 +17,15 @@ extern "C" {
 
 MLIR_DECLARE_CAPI_DIALECT_REGISTRATION(Index, index);
 
+// Currently these are opt-in
+#define GET_ENUM_CAPI_DECLS
+#define GET_ENUM_ATTR_CAPI_DECLS
+#include "mlir/Dialect/Index/IR/IndexOpsCAPIEnumAttrs.h.inc"
+#define GET_TYPE_CAPI_DECLS
+#include "mlir/Dialect/Index/IR/IndexOpsCAPITypes.h.inc"
+#define GET_ATTR_CAPI_DECLS
+#include "mlir/Dialect/Index/IR/IndexOpsCAPIAttrs.h.inc"
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/mlir/lib/CAPI/Dialect/Index.cpp b/mlir/lib/CAPI/Dialect/Index.cpp
index 84579143605f9..70868b173f66c 100644
--- a/mlir/lib/CAPI/Dialect/Index.cpp
+++ b/mlir/lib/CAPI/Dialect/Index.cpp
@@ -6,8 +6,14 @@
 //
 //===----------------------------------------------------------------------===//
 
+#define GET_OP_CLASSES
+#define GET_ATTRDEF_CLASSES
 #include "mlir-c/Dialect/Index.h"
 #include "mlir/CAPI/Registration.h"
 #include "mlir/Dialect/Index/IR/IndexDialect.h"
+#include "mlir/Dialect/Index/IR/IndexOps.h"
 
 MLIR_DEFINE_CAPI_DIALECT_REGISTRATION(Index, index, mlir::index::IndexDialect)
+
+using mlir::index::IndexCmpPredicateAttr;
+#include "mlir/Dialect/Index/IR/IndexOpsCAPIAttrs.cpp.inc"
\ No newline at end of file
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
index 5e5f4f29d44aa..f0579064a0ee3 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
@@ -83,6 +83,7 @@ struct CAPIDefGenerator : DefGenerator {
       : DefGenerator(defs, os, defType, valueType, isAttrGenerator) {}
 
   bool emitDecls(StringRef selectedDialect) override;
+  bool emitDefs(StringRef selectedDialect) override;  
 };
 } // namespace
 
@@ -97,13 +98,60 @@ static bool isUnsupportedParam(const AttrOrTypeParameter &param) {
   return false;
 }
 
+static std::string toLower(std::string s) {
+    std::transform(s.begin(), s.end(), s.begin(), ::tolower);
+    return s;
+}
+
+static void printInitType(const llvm::Init *I, llvm::raw_ostream &OS) {
+  if (!I) {
+    OS << "null Init\n";
+    return;
+  }
+
+  if (isa<llvm::UnsetInit>(I))           OS << "UnsetInit";
+  else if (isa<llvm::BitInit>(I))        OS << "BitInit";
+  else if (isa<llvm::BitsInit>(I))       OS << "BitsInit";
+  else if (isa<llvm::IntInit>(I))        OS << "IntInit";
+  else if (isa<llvm::StringInit>(I))     OS << "StringInit";
+  else if (isa<llvm::ListInit>(I))       OS << "ListInit";
+  else if (isa<llvm::DefInit>(I))        OS << "DefInit";
+  else if (isa<llvm::VarInit>(I))        OS << "VarInit";
+  else if (isa<llvm::VarBitInit>(I))     OS << "VarBitInit";
+  else if (isa<llvm::FieldInit>(I))      OS << "FieldInit";
+  else if (isa<llvm::DagInit>(I))        OS << "DagInit";
+  else if (isa<llvm::UnOpInit>(I))       OS << "UnOpInit";
+  else if (isa<llvm::BinOpInit>(I))      OS << "BinOpInit";
+  else if (isa<llvm::TernOpInit>(I))     OS << "TernOpInit";
+  else if (isa<llvm::FoldOpInit>(I))     OS << "FoldOpInit";
+  else if (isa<llvm::IsAOpInit>(I))      OS << "IsAOpInit";
+  else if (isa<llvm::ExistsOpInit>(I))   OS << "ExistsOpInit";
+  else if (isa<llvm::CondOpInit>(I))     OS << "CondOpInit";
+  else                                   OS << "Unknown Init";
+
+  OS << " : ";
+  I->print(OS);
+  OS << "\n";
+}
+
 static std::string mapParamTypeToCAPI(const AttrOrTypeParameter &param) {
   StringRef cppType = param.getCppType();
+  // if (cppType.contains("IncludeStyle")) {
+  //   llvm::errs() << "Found " << cppType << "\n";
+  //   printInitType(param.getDef(), llvm::errs());
+  // }
   if (const llvm::DefInit *defInit = dyn_cast<llvm::DefInit>(param.getDef())) {
+    // if (cppType.contains("IncludeStyle")) {
+    //   llvm::errs() << "\tDefInit as epected \n";
+    // }
     const Record *rec = defInit->getDef();
     if (rec->isSubClassOf("EnumParameter")) {
-      std::string type = "mlir";
-      type += namespacePrefix();
+      // if (cppType.contains("IncludeStyle")) {
+      //   llvm::errs() << "\tEnumParameter as epected, underlying is  \n";
+      // }
+
+      std::string type = "";
+      type += toLower(namespacePrefix());
       type += rec->getValueAsString("underlyingEnumName");
       return type;
     }
@@ -112,9 +160,7 @@ static std::string mapParamTypeToCAPI(const AttrOrTypeParameter &param) {
   }
   if (cppType == "Type")
     return "MlirType";
-  if (cppType == "Attribute" || cppType == "::mlir::DictionaryAttr" ||
-      cppType == "::mlir::ArrayAttr" || cppType == "DictionaryAttr" ||
-      cppType == "ArrayAttr")
+  if (cppType == "Attribute" || cppType.ends_with("Attr"))
     return "MlirAttribute";
   return cppType.str();
 }
@@ -130,21 +176,58 @@ getGettorParams(ArrayRef<AttrOrTypeParameter> params,
   return builderParams;
 }
 
-static void emitGettorDecl(StringRef name, ArrayRef<AttrOrTypeParameter> params,
-                           raw_ostream &os, bool isAttrGenerator) {
+static bool isEnumParam(const AttrOrTypeParameter &param) {
+  // Do I need a case for StringInits? I've seen cases where some types are 
+  // encoded as strings
+  if (const llvm::DefInit *defInit = dyn_cast<llvm::DefInit>(param.getDef())) {
+    const Record *rec = defInit->getDef();
+    return rec->isSubClassOf("EnumParameter");
+  } else {
+    return false;
+  }
+}
+
+static void emitGettorDeclOrDef(StringRef name, ArrayRef<AttrOrTypeParameter> params,
+                                raw_ostream &os, bool isAttrGenerator, bool isDeclGenerator) {
   os << "MLIR_CAPI_EXPORTED ";
   if (isAttrGenerator)
     os << "MlirAttribute ";
   else
     os << "MlirType ";
-  os << "mlir" + namespacePrefix() << name << "Get(";
+  os << llvm::StringRef(namespacePrefix()).lower() << name << "Get(";
   SmallVector<MethodParameter> params_ =
       getGettorParams(params, {{"MlirContext", "context"}});
   for (auto [i, param] : llvm::enumerate(params_)) {
     os << param.getType() << " " << param.getName()
-       << (i < params_.size() - 1 ? ", " : "");
+       << (i < (params_.size() - 1) ? ", " : "");
+  }
+  if (isDeclGenerator) {
+    os << ");\n";
+  } else {
+    os << ") {\n";
+    os << "\treturn wrap(";
+    os << name << "::get(unwrap(context)";
+    if (params.size() > 0) {
+      os << ", ";
+    } 
+    for (auto [i, param] : llvm::enumerate(params)) {
+      // If this is an enum, just use C++ static cast
+      if (isEnumParam(param)) {
+        os << "static_cast<" << param.getCppType() << ">(" << param.getName() << ")";
+      } else {
+        os << "llvm::cast<" << param.getCppType() << ">";
+        // Is this a wrapped type? If so unwrap it, otherwised don't
+        if (llvm::StringRef(mapParamTypeToCAPI(param)).starts_with("Mlir")) {
+          os << "(unwrap(" << param.getName() << "))";
+        } else {
+          os << "(" << param.getName() << ")";
+        }
+      }
+      os << (i < params.size() - 1 ? ", " : "");
+    }
+    os << "));\n";
+    os << "}\n";
   }
-  os << ");\n";
 }
 
 static void emitAccessorDecls(StringRef name,
@@ -155,7 +238,7 @@ static void emitAccessorDecls(StringRef name,
       continue;
     std::string paramName = param.getName().str();
     os << "MLIR_CAPI_EXPORTED ";
-    os << mapParamTypeToCAPI(param) << " mlir" << namespacePrefix() << name
+    os << mapParamTypeToCAPI(param) << " " << toLower(namespacePrefix()) << name
        << "Get" << withCapitalFirstLetter(param.getName().str());
     if (isAttrGenerator)
       os << "(MlirAttribute attr);";
@@ -166,12 +249,12 @@ static void emitAccessorDecls(StringRef name,
 }
 
 static void emitTypeIDDecl(StringRef name, raw_ostream &os) {
-  os << "MLIR_CAPI_EXPORTED MlirTypeID mlir" << namespacePrefix() << name
+  os << "MLIR_CAPI_EXPORTED MlirTypeID " << toLower(namespacePrefix()) << name
      << "GetTypeID();\n";
 }
 
 static void emitIsADecl(StringRef name, raw_ostream &os, bool isAttrGenerator) {
-  os << "MLIR_CAPI_EXPORTED bool mlir";
+  os << "MLIR_CAPI_EXPORTED bool mlir"; // JEG: Perhaps this one is correct?
   if (isAttrGenerator)
     os << "Attribute";
   else
@@ -199,7 +282,7 @@ static bool emitEnumDecls(ArrayRef<const Record *> records, raw_ostream &os) {
     llvm::IfDefEmitter scope(os, "GET_" + enumInfo.getEnumClassName().upper() +
                                      "_ENUM_CAPI_DECL");
     os << "// " << enumInfo.getSummary() << "\n";
-    os << "enum mlir" << namespacePrefix() << enumInfo.getEnumClassName();
+    os << "enum " << toLower(namespacePrefix()) << enumInfo.getEnumClassName();
 
     if (!enumInfo.getUnderlyingType().empty())
       os << " : " << enumInfo.getUnderlyingType();
@@ -214,6 +297,8 @@ static bool emitEnumDecls(ArrayRef<const Record *> records, raw_ostream &os) {
         os << formatv("  {0},\n", symbol);
     }
     os << "};\n";
+    // Add convenience typedef
+    os << formatv("typedef enum {0}{1} {0}{1}; \n", toLower(namespacePrefix()), enumInfo.getEnumClassName());
   }
 
   os << "\n";
@@ -248,17 +333,17 @@ static bool emitEnumAttrDecls(ArrayRef<const Record *> records, raw_ostream &os,
                                      enumInfo.getEnumClassName().upper() +
                                      "_ENUM_ATTR_CAPI_DECL");
 
-    os << "MLIR_CAPI_EXPORTED MlirAttribute mlir" << namespacePrefix()
-       << enumInfo.getEnumClassName() << "AttrGet(MlirContext context, mlir"
-       << namespacePrefix() << enumInfo.getEnumClassName() << " value);\n";
+    os << "MLIR_CAPI_EXPORTED MlirAttribute " << namespacePrefix()
+       << enumInfo.getEnumClassName() << "AttrGet(MlirContext context, "
+       << toLower(namespacePrefix()) << enumInfo.getEnumClassName() << " value);\n";
 
     std::string name = enumInfo.getEnumClassName().str() + "Attr";
     emitTypeIDDecl(name, os);
     emitIsADecl(name, os, /*isAttrGenerator*/ true);
 
-    os << "MLIR_CAPI_EXPORTED mlir" << namespacePrefix()
-       << enumInfo.getEnumClassName() << " mlir";
-    os << namespacePrefix() << name << "GetValue(MlirAttribute attr);\n";
+    os << "MLIR_CAPI_EXPORTED " << toLower(namespacePrefix())
+       << enumInfo.getEnumClassName() << " ";
+    os << toLower(namespacePrefix()) << name << "GetValue(MlirAttribute attr);\n";
   }
 
   os << "\n";
@@ -291,7 +376,7 @@ bool CAPIDefGenerator::emitDecls(StringRef selectedDialect) {
     ArrayRef<AttrOrTypeParameter> params = def.getParameters();
     emitAttrTypeHeader(name, os);
     if (!llvm::any_of(params, isUnsupportedParam))
-      emitGettorDecl(name, params, os, isAttrGenerator);
+      emitGettorDeclOrDef(name, params, os, isAttrGenerator, true);
     emitTypeIDDecl(name, os);
     emitIsADecl(name, os, isAttrGenerator);
     if (def.genAccessors() && !params.empty())
@@ -303,6 +388,25 @@ bool CAPIDefGenerator::emitDecls(StringRef selectedDialect) {
   return false;
 }
 
+bool CAPIDefGenerator::emitDefs(StringRef selectedDialect) {
+  emitSourceFileHeader((defType + "Def C API Defs").str(), os);
+
+  SmallVector<AttrOrTypeDef, 16> defs;
+  collectAllDefs(selectedDialect, defRecords, defs);
+  if (defs.empty())
+    return false;
+
+  for (const AttrOrTypeDef &def : defs) {
+    StringRef name = def.getCppClassName();
+    ArrayRef<AttrOrTypeParameter> params = def.getParameters();
+    if (!llvm::any_of(params, isUnsupportedParam)) {
+        emitGettorDeclOrDef(name, params, os, isAttrGenerator, false);
+    }
+  }
+
+  return false;
+}
+
 namespace {
 /// A specialized generator for AttrDefs.
 struct CAPIAttrDefGenerator : public CAPIDefGenerator {
@@ -344,13 +448,12 @@ static mlir::GenRegistration genAttrDecls(
       return generator.emitDecls(capiDialect);
     });
 
-// static mlir::GenRegistration
-//     genAttrDefs("gen-attrdef-capi-defs", "Generate AttrDef C API
-//     definitions",
-//                 [](const RecordKeeper &records, raw_ostream &os) {
-//                   CAPIAttrDefGenerator generator(records, os);
-//                   return generator.emitDefs(attrDialect);
-//                 });
+static mlir::GenRegistration genAttrDefs(
+  "gen-attrdef-capi-defs", "Generate AttrDef C API definitions",
+  [](const RecordKeeper &records, raw_ostream &os) {
+      CAPIAttrDefGenerator generator(records.getAllDerivedDefinitionsIfDefined("AttrDef"), os);
+      return generator.emitDefs(capiDialect);
+});
 
 //===----------------------------------------------------------------------===//
 // TypeDef

>From d31e8cd30b497a16bafc1fa7c92019693233652b Mon Sep 17 00:00:00 2001
From: jgreenbaum <j.greenbaum at computer.org>
Date: Fri, 6 Mar 2026 16:18:34 -0800
Subject: [PATCH 3/4] mlir-tblgen C API example

---
 .../mlir-c-enums-and-attrs/.gitignore         |   2 +
 .../mlir-c-enums-and-attrs/CMakeLists.txt     |  37 ++++++
 .../examples/mlir-c-enums-and-attrs/README.md |  30 +++++
 mlir/examples/mlir-c-enums-and-attrs/index.c  | 121 ++++++++++++++++++
 mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp  |  42 ------
 5 files changed, 190 insertions(+), 42 deletions(-)
 create mode 100644 mlir/examples/mlir-c-enums-and-attrs/.gitignore
 create mode 100644 mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
 create mode 100644 mlir/examples/mlir-c-enums-and-attrs/README.md
 create mode 100644 mlir/examples/mlir-c-enums-and-attrs/index.c

diff --git a/mlir/examples/mlir-c-enums-and-attrs/.gitignore b/mlir/examples/mlir-c-enums-and-attrs/.gitignore
new file mode 100644
index 0000000000000..af96791fc63ed
--- /dev/null
+++ b/mlir/examples/mlir-c-enums-and-attrs/.gitignore
@@ -0,0 +1,2 @@
+.vscode
+build
diff --git a/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt b/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
new file mode 100644
index 0000000000000..b6423e38b1e3e
--- /dev/null
+++ b/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
@@ -0,0 +1,37 @@
+cmake_minimum_required(VERSION 3.13)
+project(MlirCPlayground LANGUAGES C CXX)
+
+# Pass -DMLIR_INSTALL_DIR=<path to where MLIR is installed>
+list(APPEND CMAKE_PREFIX_PATH "${MLIR_INSTALL_DIR}/lib/cmake")
+
+# Find MLIR and LLVM
+find_package(MLIR REQUIRED CONFIG)
+find_package(LLVM REQUIRED CONFIG)
+
+# Set C++ standard
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED ON)
+
+# Include MLIR and LLVM headers
+include_directories(${MLIR_INCLUDE_DIRS})
+include_directories(${LLVM_INCLUDE_DIRS})
+include_directories(${MLIR_C_INCLUDE_DIRS})
+
+# Link MLIR and LLVM libraries
+link_directories(${MLIR_LIBRARY_DIRS})
+link_directories(${LLVM_LIBRARY_DIRS})
+# link_directories(${CIRCT_LIBRARY_DIRS})
+
+add_executable(index
+    index.c
+)
+# target_include_directories(index
+#     PRIVATE
+# )
+target_link_libraries(index 
+    PRIVATE
+
+    MLIRCAPIIR
+    MLIRCAPIFunc
+    MLIRCAPIIndex
+)
diff --git a/mlir/examples/mlir-c-enums-and-attrs/README.md b/mlir/examples/mlir-c-enums-and-attrs/README.md
new file mode 100644
index 0000000000000..d1de36a25395a
--- /dev/null
+++ b/mlir/examples/mlir-c-enums-and-attrs/README.md
@@ -0,0 +1,30 @@
+# Using the generated MLIR C API
+
+This example uses MLIR C API enumerations and attribute types generated by mlir-tblgen. In 
+particular it uses the (`index` Dialect `IndexCmpPredicateAttr`)[https://mlir.llvm.org/docs/Dialects/IndexOps/#indexcmppredicateattr] and associated (`IndexCmpPredicate`)[https://mlir.llvm.org/docs/Dialects/IndexOps/#indexcmppredicate] enumeration.
+
+# Building
+
+```
+mkdir build
+cd build
+cmake -G Ninja -DMLIR_INSTALL_DIR=<where you installed your build> ..
+ninja
+```
+
+# Running
+
+```
+build/index
+```
+
+# Output
+
+Here is the output of the program:
+
+```
+func.func @cmp_op(%arg0: index, %arg1: index) {
+  %0 = index.cmp eq(%arg0, %arg1)
+  return
+}
+```
diff --git a/mlir/examples/mlir-c-enums-and-attrs/index.c b/mlir/examples/mlir-c-enums-and-attrs/index.c
new file mode 100644
index 0000000000000..903c0d6e3bb34
--- /dev/null
+++ b/mlir/examples/mlir-c-enums-and-attrs/index.c
@@ -0,0 +1,121 @@
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <mlir-c/IR.h>
+#include <mlir-c/Support.h>
+#include <mlir-c/BuiltinTypes.h>
+#include <mlir-c/BuiltinAttributes.h>
+#include <mlir-c/Dialect/Func.h>
+#include <mlir-c/Dialect/Index.h>
+
+
+// HACK
+typedef enum indexIndexCmpPredicate indexIndexCmpPredicate;
+
+/* forward decls */
+
+// Simple callback for MLIR *Print routines. It just prints to the stdout.
+void print_callback(MlirStringRef r, void *data);
+// Load dialect and error check
+MlirDialect load_dialect(MlirContext ctx, MlirDialectHandle handle);
+
+#define HERE(ctx) (mlirLocationFileLineColGet(ctx, mlirStringRefCreateFromCString(__FILE__),\
+                                                   __LINE__, 0))
+
+int main(int argc, char **argv)
+{
+    // Initialize the MLIR context 
+    MlirContext ctx = mlirContextCreate();
+
+    // Load the HW and SV Dialects
+    MlirDialect func = load_dialect(ctx, mlirGetDialectHandle__func__());
+    MlirDialect index = load_dialect(ctx, mlirGetDialectHandle__index__());
+
+    MlirBlock top_block = mlirBlockCreate(0, NULL, NULL);
+
+    MlirType index_type = mlirIndexTypeGet(ctx);
+    MlirBlock func_body = mlirBlockCreate(0, NULL, NULL);
+    MlirRegion func_region = mlirRegionCreate();
+    mlirRegionAppendOwnedBlock(func_region, func_body);
+
+    // Add two arguments, for the a and b parameters
+    MlirValue arg_a = mlirBlockAddArgument(func_body, index_type, HERE(ctx));
+    MlirValue arg_b = mlirBlockAddArgument(func_body, index_type, HERE(ctx));
+    MlirValue cmp_args[] = {arg_a,arg_b};
+
+    MlirAttribute cmp_attr = indexIndexCmpPredicateAttrGet(ctx, EQ);
+
+    MlirNamedAttribute cmp_pred 
+            = mlirNamedAttributeGet(mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("pred")),
+                                    cmp_attr);
+    MlirNamedAttribute cmp_attrs[] = {cmp_pred};
+
+    MlirType cmp_result_type = mlirIntegerTypeGet(ctx,1);
+
+    MlirOperationState cmp_op_state 
+                = mlirOperationStateGet(mlirStringRefCreateFromCString("index.cmp"), HERE(ctx));
+    mlirOperationStateAddOperands(&cmp_op_state, 2, cmp_args);
+    mlirOperationStateAddResults(&cmp_op_state, 1, &cmp_result_type);
+    mlirOperationStateAddAttributes(&cmp_op_state, 1, cmp_attrs);
+    MlirOperation cmp_op = mlirOperationCreate(&cmp_op_state);
+    if (mlirOperationIsNull(cmp_op)) {
+        printf("cmp_op is null");
+        exit(-1);
+    }
+    mlirBlockAppendOwnedOperation(func_body, cmp_op);
+
+    MlirOperationState return_op_state 
+                = mlirOperationStateGet(mlirStringRefCreateFromCString("func.return"), HERE(ctx));
+    MlirOperation return_op = mlirOperationCreate(&return_op_state);
+    mlirBlockAppendOwnedOperation(func_body, return_op);
+
+    MlirOperationState func_state 
+                = mlirOperationStateGet(mlirStringRefCreateFromCString("func.func"), HERE(ctx));
+    // mlirOperationStateAddOperands(&func_state, 2, cmp_args);
+    MlirAttribute func_sym_attr = mlirStringAttrGet(ctx,mlirStringRefCreateFromCString("cmp_op"));
+    MlirNamedAttribute func_named_sym_attr = mlirNamedAttributeGet(
+        mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("sym_name")),
+        func_sym_attr);
+    
+    
+    MlirType func_input_types[] = {index_type, index_type};
+    MlirType func_type = mlirFunctionTypeGet(ctx, 2, func_input_types, 0, NULL);
+    MlirAttribute func_type_attr = mlirTypeAttrGet(func_type);
+
+    MlirNamedAttribute func_named_type_attr = mlirNamedAttributeGet(
+        mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("function_type")), 
+        func_type_attr);
+    MlirNamedAttribute func_attrs[] = {func_named_sym_attr, func_named_type_attr};
+    mlirOperationStateAddAttributes(&func_state, 2, func_attrs);
+    MlirRegion func_regions[] = {func_region};
+    mlirOperationStateAddOwnedRegions(&func_state, 1, func_regions);
+
+    
+
+    MlirOperation func_op = mlirOperationCreate(&func_state);
+    if (mlirOperationIsNull(func_op)) {
+        printf("func_op is null");
+        exit(-1);
+    }
+
+    MlirModule top = mlirModuleFromOperation(func_op);
+    
+    if (!mlirOperationVerify(func_op)) {
+        printf("func_op failed verification");
+        exit(-1);
+    }
+    mlirOperationDump(func_op);
+    exit(0);
+}
+
+MlirDialect load_dialect(MlirContext ctx, MlirDialectHandle handle)
+{
+    return mlirDialectHandleLoadDialect(handle, ctx);
+}
+
+// Simple callback for MLIR *Print routines. It just prints to the stdout.
+void print_callback(MlirStringRef r, void *data)
+{
+    write(0, r.data, r.length);
+}
diff --git a/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
index f0579064a0ee3..45a6e5b523143 100644
--- a/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
+++ b/mlir/tools/mlir-tblgen/AttrOrTypeCAPIGen.cpp
@@ -103,53 +103,11 @@ static std::string toLower(std::string s) {
     return s;
 }
 
-static void printInitType(const llvm::Init *I, llvm::raw_ostream &OS) {
-  if (!I) {
-    OS << "null Init\n";
-    return;
-  }
-
-  if (isa<llvm::UnsetInit>(I))           OS << "UnsetInit";
-  else if (isa<llvm::BitInit>(I))        OS << "BitInit";
-  else if (isa<llvm::BitsInit>(I))       OS << "BitsInit";
-  else if (isa<llvm::IntInit>(I))        OS << "IntInit";
-  else if (isa<llvm::StringInit>(I))     OS << "StringInit";
-  else if (isa<llvm::ListInit>(I))       OS << "ListInit";
-  else if (isa<llvm::DefInit>(I))        OS << "DefInit";
-  else if (isa<llvm::VarInit>(I))        OS << "VarInit";
-  else if (isa<llvm::VarBitInit>(I))     OS << "VarBitInit";
-  else if (isa<llvm::FieldInit>(I))      OS << "FieldInit";
-  else if (isa<llvm::DagInit>(I))        OS << "DagInit";
-  else if (isa<llvm::UnOpInit>(I))       OS << "UnOpInit";
-  else if (isa<llvm::BinOpInit>(I))      OS << "BinOpInit";
-  else if (isa<llvm::TernOpInit>(I))     OS << "TernOpInit";
-  else if (isa<llvm::FoldOpInit>(I))     OS << "FoldOpInit";
-  else if (isa<llvm::IsAOpInit>(I))      OS << "IsAOpInit";
-  else if (isa<llvm::ExistsOpInit>(I))   OS << "ExistsOpInit";
-  else if (isa<llvm::CondOpInit>(I))     OS << "CondOpInit";
-  else                                   OS << "Unknown Init";
-
-  OS << " : ";
-  I->print(OS);
-  OS << "\n";
-}
-
 static std::string mapParamTypeToCAPI(const AttrOrTypeParameter &param) {
   StringRef cppType = param.getCppType();
-  // if (cppType.contains("IncludeStyle")) {
-  //   llvm::errs() << "Found " << cppType << "\n";
-  //   printInitType(param.getDef(), llvm::errs());
-  // }
   if (const llvm::DefInit *defInit = dyn_cast<llvm::DefInit>(param.getDef())) {
-    // if (cppType.contains("IncludeStyle")) {
-    //   llvm::errs() << "\tDefInit as epected \n";
-    // }
     const Record *rec = defInit->getDef();
     if (rec->isSubClassOf("EnumParameter")) {
-      // if (cppType.contains("IncludeStyle")) {
-      //   llvm::errs() << "\tEnumParameter as epected, underlying is  \n";
-      // }
-
       std::string type = "";
       type += toLower(namespacePrefix());
       type += rec->getValueAsString("underlyingEnumName");

>From 6f0108ac13ab5aff574c01cbd6852cd385d3cb0a Mon Sep 17 00:00:00 2001
From: jgreenbaum <j.greenbaum at computer.org>
Date: Fri, 13 Mar 2026 17:46:20 -0700
Subject: [PATCH 4/4] Removing example for ease of review

---
 .../mlir-c-enums-and-attrs/.gitignore         |   2 -
 .../mlir-c-enums-and-attrs/CMakeLists.txt     |  37 ------
 .../examples/mlir-c-enums-and-attrs/README.md |  30 -----
 mlir/examples/mlir-c-enums-and-attrs/index.c  | 121 ------------------
 4 files changed, 190 deletions(-)
 delete mode 100644 mlir/examples/mlir-c-enums-and-attrs/.gitignore
 delete mode 100644 mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
 delete mode 100644 mlir/examples/mlir-c-enums-and-attrs/README.md
 delete mode 100644 mlir/examples/mlir-c-enums-and-attrs/index.c

diff --git a/mlir/examples/mlir-c-enums-and-attrs/.gitignore b/mlir/examples/mlir-c-enums-and-attrs/.gitignore
deleted file mode 100644
index af96791fc63ed..0000000000000
--- a/mlir/examples/mlir-c-enums-and-attrs/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-.vscode
-build
diff --git a/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt b/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
deleted file mode 100644
index b6423e38b1e3e..0000000000000
--- a/mlir/examples/mlir-c-enums-and-attrs/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-cmake_minimum_required(VERSION 3.13)
-project(MlirCPlayground LANGUAGES C CXX)
-
-# Pass -DMLIR_INSTALL_DIR=<path to where MLIR is installed>
-list(APPEND CMAKE_PREFIX_PATH "${MLIR_INSTALL_DIR}/lib/cmake")
-
-# Find MLIR and LLVM
-find_package(MLIR REQUIRED CONFIG)
-find_package(LLVM REQUIRED CONFIG)
-
-# Set C++ standard
-set(CMAKE_CXX_STANDARD 17)
-set(CMAKE_CXX_STANDARD_REQUIRED ON)
-
-# Include MLIR and LLVM headers
-include_directories(${MLIR_INCLUDE_DIRS})
-include_directories(${LLVM_INCLUDE_DIRS})
-include_directories(${MLIR_C_INCLUDE_DIRS})
-
-# Link MLIR and LLVM libraries
-link_directories(${MLIR_LIBRARY_DIRS})
-link_directories(${LLVM_LIBRARY_DIRS})
-# link_directories(${CIRCT_LIBRARY_DIRS})
-
-add_executable(index
-    index.c
-)
-# target_include_directories(index
-#     PRIVATE
-# )
-target_link_libraries(index 
-    PRIVATE
-
-    MLIRCAPIIR
-    MLIRCAPIFunc
-    MLIRCAPIIndex
-)
diff --git a/mlir/examples/mlir-c-enums-and-attrs/README.md b/mlir/examples/mlir-c-enums-and-attrs/README.md
deleted file mode 100644
index d1de36a25395a..0000000000000
--- a/mlir/examples/mlir-c-enums-and-attrs/README.md
+++ /dev/null
@@ -1,30 +0,0 @@
-# Using the generated MLIR C API
-
-This example uses MLIR C API enumerations and attribute types generated by mlir-tblgen. In 
-particular it uses the (`index` Dialect `IndexCmpPredicateAttr`)[https://mlir.llvm.org/docs/Dialects/IndexOps/#indexcmppredicateattr] and associated (`IndexCmpPredicate`)[https://mlir.llvm.org/docs/Dialects/IndexOps/#indexcmppredicate] enumeration.
-
-# Building
-
-```
-mkdir build
-cd build
-cmake -G Ninja -DMLIR_INSTALL_DIR=<where you installed your build> ..
-ninja
-```
-
-# Running
-
-```
-build/index
-```
-
-# Output
-
-Here is the output of the program:
-
-```
-func.func @cmp_op(%arg0: index, %arg1: index) {
-  %0 = index.cmp eq(%arg0, %arg1)
-  return
-}
-```
diff --git a/mlir/examples/mlir-c-enums-and-attrs/index.c b/mlir/examples/mlir-c-enums-and-attrs/index.c
deleted file mode 100644
index 903c0d6e3bb34..0000000000000
--- a/mlir/examples/mlir-c-enums-and-attrs/index.c
+++ /dev/null
@@ -1,121 +0,0 @@
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-#include <mlir-c/IR.h>
-#include <mlir-c/Support.h>
-#include <mlir-c/BuiltinTypes.h>
-#include <mlir-c/BuiltinAttributes.h>
-#include <mlir-c/Dialect/Func.h>
-#include <mlir-c/Dialect/Index.h>
-
-
-// HACK
-typedef enum indexIndexCmpPredicate indexIndexCmpPredicate;
-
-/* forward decls */
-
-// Simple callback for MLIR *Print routines. It just prints to the stdout.
-void print_callback(MlirStringRef r, void *data);
-// Load dialect and error check
-MlirDialect load_dialect(MlirContext ctx, MlirDialectHandle handle);
-
-#define HERE(ctx) (mlirLocationFileLineColGet(ctx, mlirStringRefCreateFromCString(__FILE__),\
-                                                   __LINE__, 0))
-
-int main(int argc, char **argv)
-{
-    // Initialize the MLIR context 
-    MlirContext ctx = mlirContextCreate();
-
-    // Load the HW and SV Dialects
-    MlirDialect func = load_dialect(ctx, mlirGetDialectHandle__func__());
-    MlirDialect index = load_dialect(ctx, mlirGetDialectHandle__index__());
-
-    MlirBlock top_block = mlirBlockCreate(0, NULL, NULL);
-
-    MlirType index_type = mlirIndexTypeGet(ctx);
-    MlirBlock func_body = mlirBlockCreate(0, NULL, NULL);
-    MlirRegion func_region = mlirRegionCreate();
-    mlirRegionAppendOwnedBlock(func_region, func_body);
-
-    // Add two arguments, for the a and b parameters
-    MlirValue arg_a = mlirBlockAddArgument(func_body, index_type, HERE(ctx));
-    MlirValue arg_b = mlirBlockAddArgument(func_body, index_type, HERE(ctx));
-    MlirValue cmp_args[] = {arg_a,arg_b};
-
-    MlirAttribute cmp_attr = indexIndexCmpPredicateAttrGet(ctx, EQ);
-
-    MlirNamedAttribute cmp_pred 
-            = mlirNamedAttributeGet(mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("pred")),
-                                    cmp_attr);
-    MlirNamedAttribute cmp_attrs[] = {cmp_pred};
-
-    MlirType cmp_result_type = mlirIntegerTypeGet(ctx,1);
-
-    MlirOperationState cmp_op_state 
-                = mlirOperationStateGet(mlirStringRefCreateFromCString("index.cmp"), HERE(ctx));
-    mlirOperationStateAddOperands(&cmp_op_state, 2, cmp_args);
-    mlirOperationStateAddResults(&cmp_op_state, 1, &cmp_result_type);
-    mlirOperationStateAddAttributes(&cmp_op_state, 1, cmp_attrs);
-    MlirOperation cmp_op = mlirOperationCreate(&cmp_op_state);
-    if (mlirOperationIsNull(cmp_op)) {
-        printf("cmp_op is null");
-        exit(-1);
-    }
-    mlirBlockAppendOwnedOperation(func_body, cmp_op);
-
-    MlirOperationState return_op_state 
-                = mlirOperationStateGet(mlirStringRefCreateFromCString("func.return"), HERE(ctx));
-    MlirOperation return_op = mlirOperationCreate(&return_op_state);
-    mlirBlockAppendOwnedOperation(func_body, return_op);
-
-    MlirOperationState func_state 
-                = mlirOperationStateGet(mlirStringRefCreateFromCString("func.func"), HERE(ctx));
-    // mlirOperationStateAddOperands(&func_state, 2, cmp_args);
-    MlirAttribute func_sym_attr = mlirStringAttrGet(ctx,mlirStringRefCreateFromCString("cmp_op"));
-    MlirNamedAttribute func_named_sym_attr = mlirNamedAttributeGet(
-        mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("sym_name")),
-        func_sym_attr);
-    
-    
-    MlirType func_input_types[] = {index_type, index_type};
-    MlirType func_type = mlirFunctionTypeGet(ctx, 2, func_input_types, 0, NULL);
-    MlirAttribute func_type_attr = mlirTypeAttrGet(func_type);
-
-    MlirNamedAttribute func_named_type_attr = mlirNamedAttributeGet(
-        mlirIdentifierGet(ctx,mlirStringRefCreateFromCString("function_type")), 
-        func_type_attr);
-    MlirNamedAttribute func_attrs[] = {func_named_sym_attr, func_named_type_attr};
-    mlirOperationStateAddAttributes(&func_state, 2, func_attrs);
-    MlirRegion func_regions[] = {func_region};
-    mlirOperationStateAddOwnedRegions(&func_state, 1, func_regions);
-
-    
-
-    MlirOperation func_op = mlirOperationCreate(&func_state);
-    if (mlirOperationIsNull(func_op)) {
-        printf("func_op is null");
-        exit(-1);
-    }
-
-    MlirModule top = mlirModuleFromOperation(func_op);
-    
-    if (!mlirOperationVerify(func_op)) {
-        printf("func_op failed verification");
-        exit(-1);
-    }
-    mlirOperationDump(func_op);
-    exit(0);
-}
-
-MlirDialect load_dialect(MlirContext ctx, MlirDialectHandle handle)
-{
-    return mlirDialectHandleLoadDialect(handle, ctx);
-}
-
-// Simple callback for MLIR *Print routines. It just prints to the stdout.
-void print_callback(MlirStringRef r, void *data)
-{
-    write(0, r.data, r.length);
-}



More information about the Mlir-commits mailing list