16#include <mlir/TableGen/Dialect.h>
18#include <llvm/ADT/StringExtras.h>
19#include <llvm/ADT/StringRef.h>
20#include <llvm/ADT/StringSwitch.h>
21#include <llvm/Support/CommandLine.h>
22#include <llvm/Support/FormatVariadic.h>
30template <
typename S>
inline void warnSkipped(
const S &methodName,
const std::string &message) {
32 llvm::errs() <<
"Warning: Skipping method '" << methodName <<
"' - " << message <<
'\n';
40 warnSkipped(methodName,
"no conversion to C API type for '" + cppType +
'\'');
106 result.reserve(str.size());
107 llvm::raw_string_ostream resultStream(result);
108 bool capitalizeNext =
true;
111 if (c ==
'_' || c ==
':') {
112 capitalizeNext =
true;
114 resultStream << (capitalizeNext ? llvm::toUpper(c) : c);
115 capitalizeNext =
false;
127 type.consume_front(
"::");
129 if (type ==
"signed" || type ==
"unsigned" || type ==
"size_t" || type ==
"char32_t" ||
130 type ==
"char16_t" || type ==
"char8_t" || type ==
"wchar_t") {
134 type.consume_front(
"signed ") || type.consume_front(
"unsigned ");
135 if (type ==
"char" || type ==
"int" || type ==
"short" || type ==
"short int" || type ==
"long" ||
136 type ==
"long int" || type ==
"long long" || type ==
"long long int") {
140 type.consume_front(
"std::");
141 if (type.consume_back(
"_t") && (type.consume_front(
"int") || type.consume_front(
"uint"))) {
143 if (type ==
"max" || type ==
"ptr") {
147 type.consume_front(
"_fast") || type.consume_front(
"_least");
148 if (type ==
"8" || type ==
"16" || type ==
"32" || type ==
"64") {
162 cppType.consume_front(
"::");
163 return cppType ==
"void" || cppType ==
"bool" || cppType ==
"float" || cppType ==
"double" ||
171 return llvm::StringSwitch<bool>(tokenText)
172 .Case(
"inline",
true)
173 .Case(
"static",
true)
174 .Case(
"virtual",
true)
175 .Case(
"explicit",
true)
176 .Case(
"constexpr",
true)
177 .Case(
"consteval",
true)
178 .Case(
"extern",
true)
179 .Case(
"mutable",
true)
180 .Case(
"friend",
true)
188 return llvm::StringSwitch<bool>(methodName)
192 .Case(
"switch",
true)
193 .Case(
"return",
true)
194 .Case(
"sizeof",
true)
195 .Case(
"decltype",
true)
196 .Case(
"alignof",
true)
197 .Case(
"typeid",
true)
198 .Case(
"static_assert",
true)
199 .Case(
"noexcept",
true)
205 cppType.consume_front(
"::");
206 return cppType ==
"llzk::DynamicAPIntValue" || cppType ==
"llvm::DynamicAPInt";
213 cppType.consume_front(
"::");
214 cppType.consume_front(
"llvm::") || cppType.consume_front(
"mlir::");
215 return cppType.starts_with(
"ArrayRef<");
220 assert(
isArrayRefType(cppType) &&
"must check `isArrayRefType()` outside");
223 cppType.consume_front(
"::");
224 cppType.consume_front(
"llvm::") || cppType.consume_front(
"mlir::");
225 cppType.consume_front(
"ArrayRef<") && cppType.consume_back(
">");
254 bool isValid()
const {
return lexer !=
nullptr; }
258 std::unique_ptr<Impl> impl;
259 clang::Lexer *lexer =
nullptr;
274 :
type(
mlir::StringRef(paramType).trim().str()),
275 name(
mlir::StringRef(paramName).trim().str()) {}
363 Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
380 if (extraDecl.empty()) {
394 llvm::raw_ostream &
os;
407#include "llzk-c/Builder.h"
408#include <mlir-c/IR.h>
425 static constexpr char fmt[] = R
"(
427MLIR_CAPI_EXPORTED bool {0}{1}IsA_{2}_{3}(Mlir{1});
444 if (!capiReturnTypeOpt.has_value()) {
448 std::string capiReturnType = capiReturnTypeOpt.value();
451 std::string paramList;
452 llvm::raw_string_ostream paramListStream(paramList);
453 paramListStream << llvm::formatv(
"Mlir{0} inp",
kind);
457 if (!capiParamTypeOpt.has_value()) {
461 const std::string &capiParamType = capiParamTypeOpt.value();
462 paramListStream <<
", " << capiParamType <<
' ' << param.name;
467 capiReturnType =
"void";
468 paramListStream <<
", MlirStringCallback callback, void *userData";
478 "MLIR_CAPI_EXPORTED {0} {1}{2}_{3}{4}({5});\n",
497 static constexpr char fmt[] = R
"(
498bool {0}{1}IsA_{2}_{3}(Mlir{1} inp) {{
499 return llvm::isa<{3}>(unwrap(inp));
502 assert(!className.empty() && "className must be set");
510 if (!capiReturnTypeOpt.has_value()) {
514 std::string capiReturnType = capiReturnTypeOpt.value();
517 std::string returnPrefix;
518 std::string returnSuffix;
519 mlir::StringRef cppReturnType = method.
returnType;
521 if (cppReturnType ==
"void") {
526 capiReturnType =
"void";
527 returnPrefix =
"std::string text;\n llvm::raw_string_ostream(text) << ";
528 returnSuffix =
";\n callback(wrap(llvm::StringRef(text)), userData)";
533 returnPrefix =
"return ";
535 }
else if (capiReturnType.starts_with(
"Mlir")) {
537 returnPrefix =
"return wrap(";
545 std::string paramList;
546 llvm::raw_string_ostream paramListStream(paramList);
547 paramListStream << llvm::formatv(
"Mlir{0} inp",
kind);
551 if (!capiParamTypeOpt.has_value()) {
555 const std::string &capiParamType = capiParamTypeOpt.value();
556 paramListStream <<
", " << capiParamType <<
' ' << param.name;
560 paramListStream <<
", MlirStringCallback callback, void *userData";
565 llvm::raw_string_ostream argListStream(argList);
566 for (
size_t i = 0; i < method.
parameters.size(); ++i) {
568 argListStream <<
", ";
573 mlir::StringRef cppParamType = param.type;
576 argListStream << param.name;
580 if (capiParamTypeOpt.has_value() && capiParamTypeOpt->starts_with(
"Mlir")) {
582 argListStream <<
"unwrap(" << param.name <<
')';
593 "{0} {1}{2}_{3}{4}({5}) {{\n",
602 " {0}llvm::cast<{1}>(unwrap(inp)).{2}({3}){4};\n",
620 static constexpr char fmt[] =
"class {0}{1}LinkTests : public CAPITest {{};\n";
626 static constexpr char fmt[] = R
"(
628TEST_F({2}{1}LinkTests, IsA_{2}_{3}) {{
629 auto test{1} = createIndex{1}();
631 // This will always return false since `createIndex*` returns an MLIR builtin
632 EXPECT_FALSE({0}{1}IsA_{2}_{3}(test{1}));
637 assert(!
className.empty() &&
"className must be set");
652 if (!capiReturnTypeOpt.has_value()) {
658 std::string dummyParams;
659 llvm::raw_string_ostream dummyParamsStream(dummyParams);
660 std::string paramList;
661 llvm::raw_string_ostream paramListStream(paramList);
666 if (!capiParamTypeOpt.has_value()) {
670 const std::string &capiParamType = capiParamTypeOpt.value();
671 std::string name = param.name;
674 if (capiParamType ==
"bool") {
675 dummyParamsStream <<
" bool " << name <<
" = false;\n";
676 }
else if (capiParamType ==
"MlirValue") {
677 dummyParamsStream <<
" auto " << name <<
" = mlirOperationGetResult(testOp, 0);\n";
678 }
else if (capiParamType ==
"MlirType") {
679 dummyParamsStream <<
" auto " << name <<
" = createIndexType();\n";
680 }
else if (capiParamType ==
"MlirAttribute") {
681 dummyParamsStream <<
" auto " << name <<
" = createIndexAttribute();\n";
682 }
else if (capiParamType ==
"MlirStringRef") {
683 dummyParamsStream <<
" auto " << name <<
" = mlirStringRefCreateFromCString(\"\");\n";
685 dummyParamsStream <<
" " << capiParamType <<
' ' << name <<
" = 0;\n";
688 dummyParamsStream <<
" " << capiParamType <<
' ' << name <<
" = {};\n";
691 paramListStream <<
", " << name;
695 paramListStream <<
", [](MlirStringRef, void *) {}, nullptr";
698 static constexpr char fmt[] = R
"(
700TEST_F({2}{1}LinkTests, {0}_{3}_{4}) {{
701 auto test{1} = createIndex{1}();
703 if ({0}{1}IsA_{2}_{3}(test{1})) {{
705 (void){0}{2}_{3}{4}(test{1}{6});
711 assert(!
className.empty() &&
"className must be set");
mlir::StringRef extractArrayRefElementType(mlir::StringRef cppType)
Extract element type from ArrayRef<...>.
llvm::cl::opt< bool > & getGenOpOperandGetters()
Return the GenOpOperandGetters option, registering it on first access.
llvm::cl::opt< std::string > & getFunctionPrefix()
Return the FunctionPrefix option, registering it on first access.
bool isPrimitiveType(mlir::StringRef cppType)
Check if a C++ type is a known primitive type.
bool isDynamicAPIntType(mlir::StringRef cppType)
Whether a parameter represents an arbitrary-precision mathematical integer.
llvm::cl::opt< bool > & getGenOpRegionGetters()
Return the GenOpRegionGetters option, registering it on first access.
void warnSkippedNoConversion(const S &methodName, const std::string &cppType)
Print warning about skipping a function due to no conversion of C++ type to C API type.
llvm::cl::opt< bool > & getGenOpResultGetters()
Return the GenOpResultGetters option, registering it on first access.
llvm::cl::opt< std::string > & getDialectName()
Return the DialectName option, registering it on first access.
std::string mapCppTypeToCapiType(mlir::StringRef cppType)
Map C++ type to corresponding C API type.
bool isCppModifierKeyword(mlir::StringRef tokenText)
Check if a token text represents a C++ modifier/specifier keyword.
std::optional< std::string > tryCppTypeToCapiType(mlir::StringRef cppType)
Convert C++ type to MLIR C API type.
bool isArrayRefType(mlir::StringRef cppType)
Check if a C++ type is an ArrayRef type.
constexpr bool WARN_SKIPPED_METHODS
bool isIntegerType(mlir::StringRef type)
Check if a C++ type is a known integer type.
bool matchesMLIRClass(mlir::StringRef cppType, mlir::StringRef typeName)
Check if a C++ type matches an MLIR type pattern.
llvm::cl::opt< bool > & getGenOpAttributeSetters()
Return the GenOpAttributeSetters option, registering it on first access.
std::optional< std::string > mapCapiTypeToBasicCppType(mlir::StringRef capiType)
Map C API type to corresponding basic (not dialect-defined) C++ type.
llvm::cl::opt< bool > & getGenOpBuild()
Return the GenOpBuild option, registering it on first access.
llvm::cl::opt< bool > & getGenOpAttributeGetters()
Return the GenOpAttributeGetters option, registering it on first access.
llvm::SmallVector< ExtraMethod > getCAPIExposedOpMethods(const mlir::tblgen::Operator &op)
Return public operation methods explicitly requested by DeclareOpInterfaceMethods traits and declared...
llvm::cl::opt< bool > & getGenExtraClassMethods()
Return the GenExtraClassMethods option, registering it on first access.
llvm::cl::opt< bool > & getGenTypeOrAttrParamGetters()
Return the GenTypeOrAttrParamGetters option, registering it on first access.
llvm::cl::opt< bool > & getGenIsA()
Return the GenIsA option, registering it on first access.
llvm::cl::opt< bool > & getGenOpOperandSetters()
Return the GenOpOperandSetters option, registering it on first access.
llvm::cl::opt< bool > & getGenTypeOrAttrGet()
Return the GenTypeOrAttrGet option, registering it on first access.
llvm::SmallVector< ExtraMethod > parseExtraMethods(mlir::StringRef extraDecl)
Parse method declarations from an extraClassDeclaration using Clang's Lexer.
std::string toPascalCase(mlir::StringRef str)
Convert names separated by underscore or colon to PascalCase.
void warnSkipped(const S &methodName, const std::string &message)
Print warning about skipping a function.
bool isCppLanguageConstruct(mlir::StringRef methodName)
Check if a method name represents a C++ control flow keyword or language construct.
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for and distribution as defined by Sections through of this document Licensor shall mean the copyright owner or entity authorized by the copyright owner that is granting the License Legal Entity shall mean the union of the acting entity and all other entities that control are controlled by or are under common control with that entity For the purposes of this definition control direct or to cause the direction or management of such whether by contract or including but not limited to software source documentation source
clang::SourceManager & getSourceManager() const
Get the source manager instance.
bool isValid() const
Check if the lexer was successfully created.
ClangLexerContext(mlir::StringRef source, mlir::StringRef bufferName="input")
Construct a lexer context for the given source code.
clang::Lexer & getLexer() const
Get the lexer instance.
virtual ~Generator()=default
Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
mlir::StringRef className
mlir::StringRef dialectNamespace
virtual void genExtraMethods(mlir::StringRef extraDecl) const
Generate code for extra methods from an extraClassDeclaration.
virtual void setNamespaceAndClassName(const mlir::tblgen::Dialect &d, mlir::StringRef cppClassName)
Set the dialect and class name for code generation.
virtual void genExtraMethod(const ExtraMethod &method) const =0
Generate code for an extra method.
std::string dialectNameCapitalized
Generator for common C implementation file elements.
Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
virtual void genIsAImpl() const
void genExtraMethod(const ExtraMethod &method) const override
Generate implementation for an extra method from an extraClassDeclaration.
virtual void genPrologue() const
~ImplementationGenerator() override=default
std::string name
The name of the parameter.
std::string type
The C++ type of the parameter.
MethodParameter(const std::string ¶mType, const std::string ¶mName)
Construct a new Method Parameter object.
Generator for common test implementation file elements.
virtual void genTestClassPrologue() const
Generate the test class prologue.
Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
~TestGenerator() override=default
void genExtraMethod(const ExtraMethod &method) const override
Generate test for an extra method from extraClassDeclaration.
virtual void genIsATest() const
Generate IsA test for a class.
virtual std::string genCleanup() const
Generate cleanup code for test methods.