LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
EnumCAPIGen.cpp
Go to the documentation of this file.
1//===- EnumCAPIGen.cpp - C API generator for enum attributes --------------===//
2//
3// Part of the LLZK Project, under the Apache License v2.0.
4// See LICENSE.txt for license information.
5// Copyright 2025 Veridise Inc.
6// SPDX-License-Identifier: Apache-2.0
7//
8//===----------------------------------------------------------------------===//
9//
10// EnumCAPIGen generates C API enum declarations from EnumInfo definitions
11// in TableGen files. This allows exposing MLIR enum attributes to C APIs.
12//
13//===----------------------------------------------------------------------===//
14
15#include "CAPIGenRegistration.h"
16#include "CommonCAPIGen.h"
17
18#include <mlir/TableGen/EnumInfo.h>
19#include <mlir/TableGen/GenInfo.h>
20
21#include <llvm/Support/CommandLine.h>
22#include <llvm/Support/FormatVariadic.h>
23#include <llvm/TableGen/Record.h>
24#include <llvm/TableGen/TableGenBackend.h>
25
26using namespace mlir;
27using namespace mlir::tblgen;
28
29namespace {
30
32struct EnumHeaderGenerator : public HeaderGenerator {
33 using HeaderGenerator::HeaderGenerator;
34 ~EnumHeaderGenerator() override = default;
35
36 void setEnumName(StringRef enumCppNamespace, StringRef enumClassName) {
37 std::string classNamePascal = toPascalCase(enumClassName);
38 this->cEnumName =
40 this->cEnumAltName = toPascalCase(enumCppNamespace) + classNamePascal;
41 this->cppQualifiedPrefix = enumCppNamespace.str() + "::" + enumClassName.str() + "::";
42 // Reset case labels for next enum
43 caseLabels.clear();
44 }
45
46 void genCaseLabel(const EnumCase &enumCase) {
47 static constexpr char fmt[] = " /// `{0}{2}`\n {1}_{2} = {3}";
48 assert(!cEnumName.empty() && "cEnumName must be set");
49 assert(!cppQualifiedPrefix.empty() && "cppQualifiedPrefix must be set");
50 this->caseLabels.push_back(
51 llvm::formatv(fmt, cppQualifiedPrefix, cEnumName, enumCase.getSymbol(), enumCase.getValue())
52 .str()
53 );
54 }
55
56 void genEnumDeclaration() const {
57 static constexpr char fmt[] = R"(
58enum {0} {{
59{2}
60};
61// type name based on prefix + dialect + enum class name
62typedef enum {0} {0};
63// type name based on cpp namespace + enum class name
64typedef enum {0} {1};
65)";
66 assert(!cEnumName.empty() && "cEnumName must be set");
67 os << llvm::formatv(fmt, cEnumName, cEnumAltName, llvm::join(caseLabels, ",\n"));
68 }
69
70protected:
71 std::string cEnumName;
75 std::string cEnumAltName;
77 std::string cppQualifiedPrefix;
79 SmallVector<std::string> caseLabels;
80};
81
83struct EnumImplementationGenerator : public ImplementationGenerator {
84 using ImplementationGenerator::ImplementationGenerator;
85 ~EnumImplementationGenerator() override = default;
86
87 void setEnumName(StringRef /*enumCppNamespace*/, StringRef enumClassName) {
88 std::string classNamePascal = toPascalCase(enumClassName);
89 this->cEnumName =
91 }
92
95 void genWrapAndUnwrapDeclaration(StringRef enumCppNamespace, StringRef enumClassName) const {
96 static constexpr char fmt[] = R"(
97 static inline {0} wrap({1} cpp) {
98 return {0}(cpp);
99 }
100 static inline {1} unwrap({0} c) {
101 return {1}(c);
102 }
103 )";
104 assert(!cEnumName.empty() && "cEnumName must be set");
105 os << llvm::formatv(fmt, cEnumName, enumCppNamespace + "::" + enumClassName);
106 }
107
108protected:
109 std::string cEnumName;
110};
111
112} // namespace
113
115static bool emitEnumCAPIHeader(const llvm::RecordKeeper &records, raw_ostream &os) {
116 emitSourceFileHeader("Enum C API Declarations", os, records);
117
118 EnumHeaderGenerator generator("Enum", os);
119 generator.genPrologue();
120
121 // Find all EnumInfo definitions
122 for (const auto *def : records.getAllDerivedDefinitionsIfDefined("EnumAttrInfo")) {
123 const EnumInfo enumInfo(def);
124 StringRef enumCppNamespace = enumInfo.getCppNamespace();
125
126 // Generate for the selected dialect only
127 // EnumInfo does not contain a Dialect reference, so filter by C++ namespace instead.
128 if (!getDialectName().empty() && !enumCppNamespace.contains_insensitive(getDialectName())) {
129 continue;
130 }
131
132 std::vector<EnumCase> enumCases = enumInfo.getAllCases();
133 if (enumCases.empty()) {
134 continue;
135 }
136
137 generator.setEnumName(enumCppNamespace, enumInfo.getEnumClassName());
138 for (EnumCase &enumCase : enumCases) {
139 generator.genCaseLabel(enumCase);
140 }
141 generator.genEnumDeclaration();
142 }
143
144 generator.genEpilogue();
145 return false;
146}
147
149static bool emitEnumCAPIImpl(const llvm::RecordKeeper &records, raw_ostream &os) {
150 emitSourceFileHeader("Enum C API Implementations", os, records);
151
152 EnumImplementationGenerator generator("Enum", os);
153
154 // Find all EnumInfo definitions
155 for (const auto *def : records.getAllDerivedDefinitionsIfDefined("EnumAttrInfo")) {
156 const EnumInfo enumInfo(def);
157 StringRef enumCppNamespace = enumInfo.getCppNamespace();
158
159 // Generate for the selected dialect only
160 // EnumInfo does not contain a Dialect reference, so filter by C++ namespace instead.
161 if (!getDialectName().empty() && !enumCppNamespace.contains_insensitive(getDialectName())) {
162 continue;
163 }
164
165 std::vector<EnumCase> enumCases = enumInfo.getAllCases();
166 if (enumCases.empty()) {
167 continue;
168 }
169
170 generator.setEnumName(enumCppNamespace, enumInfo.getEnumClassName());
171 generator.genWrapAndUnwrapDeclaration(enumCppNamespace, enumInfo.getEnumClassName());
172 }
173 return false;
174}
175
177 static mlir::GenRegistration genEnumCAPIHeader(
178 "gen-enum-capi-header", "Generate C API enum declarations from EnumInfo definitions",
179 &emitEnumCAPIHeader
180 );
181
182 static mlir::GenRegistration genEnumCAPIImpl(
183 "gen-enum-capi-impl", "Generate enum C API wrap/unwrap implementations", &emitEnumCAPIImpl
184 );
185}
llvm::cl::opt< std::string > & getFunctionPrefix()
Return the FunctionPrefix option, registering it on first access.
llvm::cl::opt< std::string > & getDialectName()
Return the DialectName option, registering it on first access.
std::string toPascalCase(mlir::StringRef str)
Convert names separated by underscore or colon to PascalCase.
void registerEnumCAPIGenerators()
Register the enum C API generators before command-line parsing.
Generator for common C header file elements.
Generator for common C implementation file elements.