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 +
'\'');
51extern llvm::cl::OptionCategory
OpGenCat;
56extern llvm::cl::opt<bool>
GenIsA;
81 result.reserve(str.size());
82 llvm::raw_string_ostream resultStream(result);
83 bool capitalizeNext =
true;
86 if (c ==
'_' || c ==
':') {
87 capitalizeNext =
true;
89 resultStream << (capitalizeNext ? llvm::toUpper(c) : c);
90 capitalizeNext =
false;
102 type.consume_front(
"::");
104 if (type ==
"signed" || type ==
"unsigned" || type ==
"size_t" || type ==
"char32_t" ||
105 type ==
"char16_t" || type ==
"char8_t" || type ==
"wchar_t") {
109 type.consume_front(
"signed ") || type.consume_front(
"unsigned ");
110 if (type ==
"char" || type ==
"int" || type ==
"short" || type ==
"short int" || type ==
"long" ||
111 type ==
"long int" || type ==
"long long" || type ==
"long long int") {
115 type.consume_front(
"std::");
116 if (type.consume_back(
"_t") && (type.consume_front(
"int") || type.consume_front(
"uint"))) {
118 if (type ==
"max" || type ==
"ptr") {
122 type.consume_back(
"_fast") || type.consume_back(
"_least");
123 if (type ==
"8" || type ==
"16" || type ==
"32" || type ==
"64") {
137 cppType.consume_front(
"::");
138 return cppType ==
"void" || cppType ==
"bool" || cppType ==
"float" || cppType ==
"double" ||
146 return llvm::StringSwitch<bool>(tokenText)
147 .Case(
"inline",
true)
148 .Case(
"static",
true)
149 .Case(
"virtual",
true)
150 .Case(
"explicit",
true)
151 .Case(
"constexpr",
true)
152 .Case(
"consteval",
true)
153 .Case(
"extern",
true)
154 .Case(
"mutable",
true)
155 .Case(
"friend",
true)
163 return llvm::StringSwitch<bool>(methodName)
167 .Case(
"switch",
true)
168 .Case(
"return",
true)
169 .Case(
"sizeof",
true)
170 .Case(
"decltype",
true)
171 .Case(
"alignof",
true)
172 .Case(
"typeid",
true)
173 .Case(
"static_assert",
true)
174 .Case(
"noexcept",
true)
182 cppType.consume_front(
"::");
183 cppType.consume_front(
"llvm::") || cppType.consume_front(
"mlir::");
184 return cppType ==
"APInt";
191 cppType.consume_front(
"::");
192 cppType.consume_front(
"llvm::") || cppType.consume_front(
"mlir::");
193 return cppType.starts_with(
"ArrayRef<");
198 assert(
isArrayRefType(cppType) &&
"must check `isArrayRefType()` outside");
201 cppType.consume_front(
"::");
202 cppType.consume_front(
"llvm::") || cppType.consume_front(
"mlir::");
203 cppType.consume_front(
"ArrayRef<") && cppType.consume_back(
">");
232 bool isValid()
const {
return lexer !=
nullptr; }
236 std::unique_ptr<Impl> impl;
237 clang::Lexer *lexer =
nullptr;
252 :
type(
mlir::StringRef(paramType).trim().str()),
253 name(
mlir::StringRef(paramName).trim().str()) {}
324 Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
340 if (extraDecl.empty()) {
354 llvm::raw_ostream &
os;
367#include "llzk-c/Builder.h"
368#include <mlir-c/IR.h>
385 static constexpr char fmt[] = R
"(
386/* Returns true if the {1} is a {4}::{3}. */
387MLIR_CAPI_EXPORTED bool {0}{1}IsA{2}{3}(Mlir{1});
389 assert(dialect && "Dialect must be set");
404 if (!capiReturnTypeOpt.has_value()) {
408 std::string capiReturnType = capiReturnTypeOpt.value();
411 std::string paramList;
412 llvm::raw_string_ostream paramListStream(paramList);
413 paramListStream << llvm::formatv(
"Mlir{0} inp",
kind);
417 if (!capiParamTypeOpt.has_value()) {
421 std::string capiParamType = capiParamTypeOpt.value();
422 paramListStream <<
", " << capiParamType <<
' ' << param.name;
426 std::string docComment =
429 os << llvm::formatv(
"\n/* {0} */\n", docComment);
431 "MLIR_CAPI_EXPORTED {0} {1}{2}{3}{4}({5});\n",
448 static constexpr char fmt[] = R
"(
449bool {0}{1}IsA{2}{3}(Mlir{1} inp) {{
450 return llvm::isa<{3}>(unwrap(inp));
453 assert(!className.empty() && "className must be set");
461 if (!capiReturnTypeOpt.has_value()) {
465 std::string capiReturnType = capiReturnTypeOpt.value();
468 std::string returnPrefix;
469 std::string returnSuffix;
470 mlir::StringRef cppReturnType = method.
returnType;
472 if (cppReturnType ==
"void") {
480 returnPrefix =
"return ";
482 }
else if (capiReturnType.starts_with(
"Mlir") ||
isAPIntType(cppReturnType)) {
484 returnPrefix =
"return wrap(";
492 std::string paramList;
493 llvm::raw_string_ostream paramListStream(paramList);
494 paramListStream << llvm::formatv(
"Mlir{0} inp",
kind);
498 if (!capiParamTypeOpt.has_value()) {
502 std::string capiParamType = capiParamTypeOpt.value();
503 paramListStream <<
", " << capiParamType <<
' ' << param.name;
508 llvm::raw_string_ostream argListStream(argList);
509 for (
size_t i = 0; i < method.
parameters.size(); ++i) {
511 argListStream <<
", ";
516 mlir::StringRef cppParamType = param.type;
519 argListStream << param.name;
522 argListStream <<
"unwrap(" << param.name <<
')';
526 if (capiParamTypeOpt.has_value() && capiParamTypeOpt->starts_with(
"Mlir")) {
528 argListStream <<
"unwrap(" << param.name <<
')';
539 "{0} {1}{2}{3}{4}({5}) {{\n",
548 " {0}llvm::cast<{1}>(unwrap(inp)).{2}({3}){4};\n",
566 static constexpr char fmt[] =
"class {0}{1}LinkTests : public CAPITest {{};\n";
572 static constexpr char fmt[] = R
"(
573// This test ensures {0}{1}IsA{2}{3} links properly.
574TEST_F({2}{1}LinkTests, IsA_{2}{3}) {{
575 auto test{1} = createIndex{1}();
577 // This will always return false since `createIndex*` returns an MLIR builtin
578 EXPECT_FALSE({0}{1}IsA{2}{3}(test{1}));
583 assert(!className.empty() && "className must be set");
598 if (!capiReturnTypeOpt.has_value()) {
604 std::string dummyParams;
605 llvm::raw_string_ostream dummyParamsStream(dummyParams);
606 std::string paramList;
607 llvm::raw_string_ostream paramListStream(paramList);
612 if (!capiParamTypeOpt.has_value()) {
616 std::string capiParamType = capiParamTypeOpt.value();
617 std::string name = param.name;
620 if (capiParamType ==
"bool") {
621 dummyParamsStream <<
" bool " << name <<
" = false;\n";
622 }
else if (capiParamType ==
"MlirValue") {
623 dummyParamsStream <<
" auto " << name <<
" = mlirOperationGetResult(testOp, 0);\n";
624 }
else if (capiParamType ==
"MlirType") {
625 dummyParamsStream <<
" auto " << name <<
" = createIndexType();\n";
626 }
else if (capiParamType ==
"MlirAttribute") {
627 dummyParamsStream <<
" auto " << name <<
" = createIndexAttribute();\n";
628 }
else if (capiParamType ==
"MlirStringRef") {
629 dummyParamsStream <<
" auto " << name <<
" = mlirStringRefCreateFromCString(\"\");\n";
631 dummyParamsStream <<
" " << capiParamType <<
' ' << name <<
" = 0;\n";
634 dummyParamsStream <<
" " << capiParamType <<
' ' << name <<
" = {};\n";
637 paramListStream <<
", " << name;
640 static constexpr char fmt[] = R
"(
641// This test ensures {0}{2}{3}{4} links properly.
642TEST_F({2}{1}LinkTests, {0}_{3}_{4}) {{
643 auto test{1} = createIndex{1}();
645 if ({0}{1}IsA{2}{3}(test{1})) {{
647 (void){0}{2}{3}{4}(test{1}{6});
653 assert(!className.empty() && "className must be set");
mlir::StringRef extractArrayRefElementType(mlir::StringRef cppType)
Extract element type from ArrayRef<...>
llvm::cl::OptionCategory OpGenCat
llvm::cl::opt< bool > GenOpOperandSetters
llvm::cl::opt< bool > GenTypeOrAttrParamGetters
bool isPrimitiveType(mlir::StringRef cppType)
Check if a C++ type is a known primitive type.
llvm::cl::opt< bool > GenTypeOrAttrGet
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 > GenIsA
std::string mapCppTypeToCapiType(mlir::StringRef cppType)
Map C++ type to corresponding C API type.
llvm::cl::opt< bool > GenOpBuild
llvm::cl::opt< std::string > DialectName
bool isCppModifierKeyword(mlir::StringRef tokenText)
Check if a token text represents a C++ modifier/specifier keyword.
bool isAPIntType(mlir::StringRef cppType)
Check if a C++ type is APInt.
llvm::cl::opt< std::string > FunctionPrefix
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.
llvm::cl::opt< bool > GenOpRegionGetters
constexpr bool WARN_SKIPPED_METHODS
bool isIntegerType(mlir::StringRef type)
Check if a C++ type is a known integer type.
llvm::cl::opt< bool > GenOpResultGetters
llvm::cl::opt< bool > GenOpAttributeGetters
bool matchesMLIRClass(mlir::StringRef cppType, mlir::StringRef typeName)
Check if a C++ type matches an MLIR type pattern.
llvm::cl::opt< bool > GenOpAttributeSetters
llvm::cl::opt< bool > GenOpOperandGetters
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.
llvm::cl::opt< bool > GenExtraClassMethods
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 void setDialectAndClassName(const mlir::tblgen::Dialect *d, mlir::StringRef cppClassName)
Set the dialect and class name for code generation.
virtual ~Generator()=default
Generator(std::string_view recordKind, llvm::raw_ostream &outputStream)
mlir::StringRef className
virtual void genExtraMethods(mlir::StringRef extraDecl) const
Generate code for extra methods from an extraClassDeclaration
const mlir::tblgen::Dialect * dialect
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 ~ImplementationGenerator()=default
virtual void genIsAImpl() const
virtual void genExtraMethod(const ExtraMethod &method) const override
Generate implementation for an extra method from an extraClassDeclaration
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)
virtual ~TestGenerator()=default
virtual void genIsATest() const
Generate IsA test for a class.
virtual std::string genCleanup() const
Generate cleanup code for test methods.
virtual void genExtraMethod(const ExtraMethod &method) const override
Generate test for an extra method from extraClassDeclaration.