LLZK 3.0.0
An open-source IR for Zero Knowledge (ZK) circuits
Loading...
Searching...
No Matches
OpCAPIGen.cpp
Go to the documentation of this file.
1//===- OpCAPIGen.cpp - C API generator for operations ---------------------===//
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// OpCAPIGen uses the description of operations to generate C API for the ops.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CAPIGenRegistration.h"
15#include "CommonCAPIGen.h"
16#include "OpCAPIParamHelper.h"
17
18#include <mlir/TableGen/GenInfo.h>
19#include <mlir/TableGen/Operator.h>
20
21#include <llvm/Support/CommandLine.h>
22#include <llvm/Support/FormatVariadic.h>
23#include <llvm/TableGen/Error.h>
24#include <llvm/TableGen/Record.h>
25#include <llvm/TableGen/TableGenBackend.h>
26
27#include <string>
28#include <vector>
29
30using namespace mlir;
31using namespace mlir::tblgen;
32
35 void setOperandName(mlir::StringRef name) { this->operandNameCapitalized = toPascalCase(name); }
36 void setAttributeName(mlir::StringRef name) { this->attrNameCapitalized = toPascalCase(name); }
37 void setResultName(mlir::StringRef name, int resultIndex) {
39 name.empty() ? llvm::formatv("Result{0}", resultIndex).str() : toPascalCase(name);
40 }
41 void setRegionName(mlir::StringRef name, unsigned regionIndex) {
43 name.empty() ? llvm::formatv("Region{0}", regionIndex).str() : toPascalCase(name);
44 }
45
46protected:
51};
52
55 using HeaderGenerator::HeaderGenerator;
56 ~OpHeaderGenerator() override = default;
57
58 void genOpBuildDecl(const std::string &params) const {
59 static constexpr char fmt[] = R"(
61MLIR_CAPI_EXPORTED MlirOperation {0}{1}_{2}Build(MlirOpBuilder builder, MlirLocation location{3});
62)";
63 assert(!className.empty() && "className must be set");
64 os << llvm::formatv(
65 fmt,
66 getFunctionPrefix(), // {0}
68 className, // {2}
69 params, // {3}
70 dialectNamespace // {4}
71 );
72 }
73
74 void genOperandGetterDecl() const {
75 static constexpr char fmt[] = R"(
77MLIR_CAPI_EXPORTED MlirValue {0}{1}_{2}Get{3}(MlirOperation op);
78)";
79 assert(!className.empty() && "className must be set");
80 assert(!operandNameCapitalized.empty() && "operandName must be set");
81 os << llvm::formatv(
82 fmt,
83 getFunctionPrefix(), // {0}
85 className, // {2}
87 dialectNamespace // {4}
88 );
89 }
90
91 void genOperandSetterDecl() const {
92 static constexpr char fmt[] = R"(
94MLIR_CAPI_EXPORTED void {0}{1}_{2}Set{3}(MlirOperation op, MlirValue value);
95)";
96 assert(!className.empty() && "className must be set");
97 assert(!operandNameCapitalized.empty() && "operandName must be set");
98 os << llvm::formatv(
99 fmt,
100 getFunctionPrefix(), // {0}
102 className, // {2}
104 dialectNamespace // {4}
105 );
106 }
107
108 void genVariadicOperandGetterDecl() const {
109 static constexpr char fmt[] = R"(
111MLIR_CAPI_EXPORTED intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op);
112
113
114MLIR_CAPI_EXPORTED MlirValue {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index);
115)";
116 assert(!className.empty() && "className must be set");
117 assert(!operandNameCapitalized.empty() && "operandName must be set");
118 os << llvm::formatv(
119 fmt,
120 getFunctionPrefix(), // {0}
122 className, // {2}
124 dialectNamespace // {4}
125
126 );
127 }
128
130 static constexpr char fmt[] = R"(
132MLIR_CAPI_EXPORTED void {0}{1}_{2}Set{3}(MlirOperation op, intptr_t count, MlirValue const *values);
133)";
134 assert(!className.empty() && "className must be set");
135 assert(!operandNameCapitalized.empty() && "operandName must be set");
136 os << llvm::formatv(
137 fmt,
138 getFunctionPrefix(), // {0}
140 className, // {2}
142 dialectNamespace // {4}
144 );
145 }
146
148 static constexpr char fmt[] = R"(
152MLIR_CAPI_EXPORTED void {0}{1}_{2}Set{3}(MlirOperation op, intptr_t groupCount, MlirValueRange const *groups);
153)";
154 assert(!className.empty() && "className must be set");
155 assert(!operandNameCapitalized.empty() && "operandName must be set");
156 os << llvm::formatv(
157 fmt,
158 getFunctionPrefix(), // {0}
160 className, // {2}
162 dialectNamespace // {4}
163 );
164 }
165
166 void genAttributeGetterDecl() const {
167 static constexpr char fmt[] = R"(
169MLIR_CAPI_EXPORTED MlirAttribute {0}{1}_{2}Get{3}(MlirOperation op);
170)";
171 assert(!className.empty() && "className must be set");
172 assert(!attrNameCapitalized.empty() && "attrName must be set");
173 os << llvm::formatv(
174 fmt,
175 getFunctionPrefix(), // {0}
177 className, // {2}
178 attrNameCapitalized, // {3}
179 dialectNamespace // {4}
180 );
181 }
182
183 void genAttributeSetterDecl() const {
184 static constexpr char fmt[] = R"(
185/// Set {3} attribute of {4}::{2} Operation.
186MLIR_CAPI_EXPORTED void {0}{1}_{2}Set{3}(MlirOperation op, MlirAttribute attr);
187)";
188 assert(!className.empty() && "className must be set");
189 assert(!attrNameCapitalized.empty() && "attrName must be set");
190 os << llvm::formatv(
191 fmt,
192 getFunctionPrefix(), // {0}
194 className, // {2}
195 attrNameCapitalized, // {3}
196 dialectNamespace // {4}
197 );
198 }
200 void genResultGetterDecl() const {
201 static constexpr char fmt[] = R"(
203MLIR_CAPI_EXPORTED MlirValue {0}{1}_{2}Get{3}(MlirOperation op);
204)";
205 assert(!className.empty() && "className must be set");
206 assert(!resultNameCapitalized.empty() && "resultName must be set");
207 os << llvm::formatv(
208 fmt,
209 getFunctionPrefix(), // {0}
211 className, // {2}
214 );
215 }
216
217 void genVariadicResultGetterDecl() const {
218 static constexpr char fmt[] = R"(
220MLIR_CAPI_EXPORTED intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op);
221
223MLIR_CAPI_EXPORTED MlirValue {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index);
224)";
225 assert(!className.empty() && "className must be set");
226 assert(!resultNameCapitalized.empty() && "resultName must be set");
227 os << llvm::formatv(
228 fmt,
229 getFunctionPrefix(), // {0}
231 className, // {2}
233 dialectNamespace // {4}
234 );
235 }
236
237 void genRegionGetterDecl() const {
238 static constexpr char fmt[] = R"(
240MLIR_CAPI_EXPORTED MlirRegion {0}{1}_{2}Get{3}(MlirOperation op);
241)";
242 assert(!className.empty() && "className must be set");
243 assert(!regionNameCapitalized.empty() && "regionName must be set");
244 os << llvm::formatv(
245 fmt,
246 getFunctionPrefix(), // {0}
248 className, // {2}
250 dialectNamespace // {4}
251 );
252 }
253
254 void genVariadicRegionGetterDecl() const {
255 static constexpr char fmt[] = R"(
257MLIR_CAPI_EXPORTED intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op);
258
260MLIR_CAPI_EXPORTED MlirRegion {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index);
261)";
262 assert(!className.empty() && "className must be set");
263 assert(!regionNameCapitalized.empty() && "regionName must be set");
264 os << llvm::formatv(
265 fmt,
266 getFunctionPrefix(), // {0}
268 className, // {2}
270 dialectNamespace // {4}
271 );
272 }
273};
274
280static std::string generateCAPIBuildParams(const Operator &op) {
281 struct : GenStringFromOpPieces {
282 void genResult(
283 llvm::raw_ostream &os, const NamedTypeConstraint &result, const std::string &resultName
284 ) override {
285 if (result.isVariadic()) {
286 os << llvm::formatv(", intptr_t {0}Size, MlirType const *{0}Types", resultName);
287 } else {
288 os << llvm::formatv(", MlirType {0}Type", resultName);
289 }
290 }
291 void genOperand(llvm::raw_ostream &os, const NamedTypeConstraint &operand) override {
292 if (operand.isVariadic()) {
293 os << llvm::formatv(", intptr_t {0}Size, MlirValue const *{0}", operand.name);
294 } else {
295 os << llvm::formatv(", MlirValue {0}", operand.name);
296 }
297 }
298 void genAttribute(llvm::raw_ostream &os, const NamedAttribute &attr) override {
299 std::optional<std::string> attrType = tryCppTypeToCapiType(attr.attr.getStorageType());
300 os << llvm::formatv(", {0} {1}", attrType.value_or("MlirAttribute"), attr.name);
301 }
302 void genRegion(llvm::raw_ostream &os, const mlir::tblgen::NamedRegion &region) override {
303 if (region.isVariadic()) {
304 os << llvm::formatv(", unsigned {0}Count", region.name);
305 }
306 }
307 } paramStringGenerator;
308 return paramStringGenerator.gen(op);
309}
310
312static bool emitOpCAPIHeader(const llvm::RecordKeeper &records, raw_ostream &os) {
313 emitSourceFileHeader("Op C API Declarations", os, records);
314
315 OpHeaderGenerator generator("Operation", os);
316 generator.genPrologue();
317
318 for (const auto *def : records.getAllDerivedDefinitions("Op")) {
319 const Operator op(def);
320 const Dialect &dialect = op.getDialect();
321
322 // Generate for the selected dialect only (specified via -dialect command-line option)
323 if (dialect.getName() != getDialectName()) {
324 continue;
325 }
326
327 generator.setNamespaceAndClassName(dialect, op.getCppClassName());
328
329 // Generate "Build" function
330 if (getGenOpBuild() && !op.skipDefaultBuilders()) {
331 generator.genOpBuildDecl(generateCAPIBuildParams(op));
332 }
333
334 // Generate IsA check
335 if (getGenIsA()) {
336 generator.genIsADecl();
337 }
338
339 // Generate operand getters and setters
340 for (int i = 0, e = op.getNumOperands(); i < e; ++i) {
341 const auto &operand = op.getOperand(i);
342 generator.setOperandName(operand.name);
343 if (operand.isVariadic()) {
345 generator.genVariadicOperandGetterDecl();
346 }
348 if (operand.isVariadicOfVariadic()) {
349 generator.genVariadicOfVariadicOperandSetterDecl();
350 } else {
351 generator.genVariadicOperandSetterDecl();
352 }
353 }
354 } else {
356 generator.genOperandGetterDecl();
357 }
359 generator.genOperandSetterDecl();
360 }
361 }
362 }
363
364 // Generate attribute getters and setters
365 for (const auto &namedAttr : op.getAttributes()) {
366 generator.setAttributeName(namedAttr.name);
368 generator.genAttributeGetterDecl();
369 }
371 generator.genAttributeSetterDecl();
372 }
373 }
374
375 // Generate result getters
376 if (getGenOpResultGetters()) {
377 for (int i = 0, e = op.getNumResults(); i < e; ++i) {
378 const auto &result = op.getResult(i);
379 generator.setResultName(result.name, i);
380 if (result.isVariadic()) {
381 generator.genVariadicResultGetterDecl();
382 } else {
383 generator.genResultGetterDecl();
384 }
385 }
386 }
387
388 // Generate region getters
389 if (getGenOpRegionGetters()) {
390 for (unsigned i = 0, e = op.getNumRegions(); i < e; ++i) {
391 const auto &region = op.getRegion(i);
392 generator.setRegionName(region.name, i);
393 if (region.isVariadic()) {
394 generator.genVariadicRegionGetterDecl();
395 } else {
396 generator.genRegionGetterDecl();
397 }
398 }
399 }
400
401 // Generate wrappers for interface and extra class methods.
403 for (const ExtraMethod &method : getCAPIExposedOpMethods(op)) {
404 generator.genExtraMethod(method);
405 }
406 }
407 }
408
409 generator.genEpilogue();
410 return false;
411}
412
415 using ImplementationGenerator::ImplementationGenerator;
416 ~OpImplementationGenerator() override = default;
417
418 void genPrologue() const override {
419 os << R"(
420#include <limits>
421
422using namespace mlir;
423using namespace llvm;
424)";
425 }
431 void genOpBuildImpl(
432 const std::string &operationName, const std::string &params, const std::string &assignments
433 ) const {
434 static constexpr char fmt[] = R"(
435MlirOperation {0}{1}_{2}Build(MlirOpBuilder builder, MlirLocation location{3}) {{
436 MlirOperationState state = mlirOperationStateGet(mlirStringRefCreateFromCString("{4}"), location);
437{5}
438 return mlirOpBuilderInsert(builder, mlirOperationCreate(&state));
439}
440)";
441 assert(!className.empty() && "className must be set");
442 os << llvm::formatv(
443 fmt,
444 getFunctionPrefix(), // {0}
446 className, // {2}
447 params, // {3}
448 operationName, // {4}
449 assignments // {5}
450 );
451 }
452
453 void genOperandGetterImpl(int index) const {
454 static constexpr char fmt[] = R"(
455MlirValue {0}{1}_{2}Get{3}(MlirOperation op) {{
456 auto range = llvm::cast<{2}>(unwrap(op)).getODSOperandIndexAndLength({4});
457 assert(range.second == 1 && "expected fixed operand segment size");
458 assert(
459 static_cast<uintptr_t>(range.first) <= static_cast<uintptr_t>(std::numeric_limits<intptr_t>::max()) &&
460 "operand index exceeds intptr_t range"
461 );
462 return mlirOperationGetOperand(op, static_cast<intptr_t>(range.first));
463}
464)";
465 assert(!className.empty() && "className must be set");
466 assert(!operandNameCapitalized.empty() && "operandName must be set");
467 os << llvm::formatv(
468 fmt,
469 getFunctionPrefix(), // {0}
471 className, // {2}
473 index // {4}
474 );
475 }
476
477 void genOperandSetterImpl(int index) const {
478 static constexpr char fmt[] = R"(
479void {0}{1}_{2}Set{3}(MlirOperation op, MlirValue value) {{
480 auto range = llvm::cast<{2}>(unwrap(op)).getODSOperandIndexAndLength({4});
481 assert(range.second == 1 && "expected fixed operand segment size");
482 assert(
483 static_cast<uintptr_t>(range.first) <= static_cast<uintptr_t>(std::numeric_limits<intptr_t>::max()) &&
484 "operand index exceeds intptr_t range"
485 );
486 mlirOperationSetOperand(op, static_cast<intptr_t>(range.first), value);
487}
488)";
489 assert(!className.empty() && "className must be set");
490 assert(!operandNameCapitalized.empty() && "operandName must be set");
491 os << llvm::formatv(
492 fmt,
493 getFunctionPrefix(), // {0}
495 className, // {2}
497 index // {4}
498 );
499 }
500
501 void genVariadicOperandGetterImpl(int index) const {
502 static constexpr char fmt[] = R"(
503intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op) {{
504 auto range = llvm::cast<{2}>(unwrap(op)).getODSOperandIndexAndLength({4});
505 return range.second;
506}
507
508MlirValue {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index) {{
509 auto range = llvm::cast<{2}>(unwrap(op)).getODSOperandIndexAndLength({4});
510 assert(index >= 0 && index < range.second && "variadic operand index out of range");
511 assert(
512 static_cast<uintptr_t>(range.first) <= static_cast<uintptr_t>(std::numeric_limits<intptr_t>::max()) &&
513 "operand index exceeds intptr_t range"
514 );
515 return mlirOperationGetOperand(op, static_cast<intptr_t>(range.first) + index);
516}
517)";
518 assert(!className.empty() && "className must be set");
519 assert(!operandNameCapitalized.empty() && "operandName must be set");
520 os << llvm::formatv(
521 fmt,
522 getFunctionPrefix(), // {0}
524 className, // {2}
526 index // {4}
527 );
528 }
529
530 // Delegate to the ODS-generated mutable accessor. assign() keeps operandSegmentSizes in sync
531 // automatically via MutableOperandRange::updateLength.
532 void genVariadicOperandSetterImpl() const {
533 static constexpr char fmt[] = R"(
534void {0}{1}_{2}Set{3}(MlirOperation op, intptr_t count, MlirValue const *values) {{
535 if (count < 0)
536 return;
537 ::llvm::SmallVector<::mlir::Value> vals;
538 vals.reserve(static_cast<size_t>(count));
539 for (intptr_t i = 0; i < count; ++i)
540 vals.push_back(unwrap(values[i]));
541 ::llvm::cast<{2}>(unwrap(op)).get{3}Mutable().assign(vals);
542}
543)";
544 assert(!className.empty() && "className must be set");
545 assert(!operandNameCapitalized.empty() && "operandName must be set");
546 os << llvm::formatv(
547 fmt,
548 getFunctionPrefix(), // {0}
550 className, // {2}
552 );
553 }
554
555 // For VariadicOfVariadic operands the caller passes one MlirValueRange per group. The flat
556 // operand list is rebuilt from all groups, operandSegmentSizes is updated automatically by
557 // join().assign(), and the per-group segment-size attribute (whose name is read from the
558 // TableGen constraint via getVariadicOfVariadicSegmentSizeAttr()) is updated explicitly.
559 void genVariadicOfVariadicOperandSetterImpl(mlir::StringRef segSizeAttrName) const {
560 static constexpr char fmt[] = R"(
561void {0}{1}_{2}Set{3}(MlirOperation op, intptr_t groupCount, MlirValueRange const *groups) {{
562 if (groupCount < 0)
563 return;
564
565 ::llvm::SmallVector<::mlir::Value> vals;
566 for (intptr_t g = 0; g < groupCount; ++g) {{
567 assert(groups[g].size >= 0 && "group size must be non-negative");
568 for (intptr_t i = 0; i < groups[g].size; ++i) {{
569 vals.push_back(unwrap(groups[g].values[i]));
570 }
571 }
572 ::llvm::cast<{2}>(unwrap(op)).get{3}Mutable().join().assign(vals);
574 ::llvm::SmallVector<int32_t> newGroupSizes;
575 newGroupSizes.reserve(static_cast<size_t>(groupCount));
576 for (intptr_t g = 0; g < groupCount; ++g) {{
577 assert(
578 groups[g].size <= static_cast<intptr_t>(std::numeric_limits<int32_t>::max()) &&
579 "group size exceeds int32_t range"
580 );
581 newGroupSizes.push_back(static_cast<int32_t>(groups[g].size));
582 }
583 MlirContext ctx = mlirOperationGetContext(op);
584 assert(
585 newGroupSizes.size() <= static_cast<size_t>(std::numeric_limits<intptr_t>::max()) &&
586 "group count exceeds intptr_t range"
587 );
588 mlirOperationSetAttributeByName(
589 op, mlirStringRefCreateFromCString("{4}"),
590 mlirDenseI32ArrayGet(ctx, static_cast<intptr_t>(newGroupSizes.size()), newGroupSizes.data())
591 );
592}
593)";
594 assert(!className.empty() && "className must be set");
595 assert(!operandNameCapitalized.empty() && "operandName must be set");
596 os << llvm::formatv(
597 fmt,
598 getFunctionPrefix(), // {0}
600 className, // {2}
602 segSizeAttrName // {4}
603 );
604 }
605
606 void genAttributeGetterImpl(mlir::StringRef attrName) const {
607 static constexpr char fmt[] = R"(
608MlirAttribute {0}{1}_{2}Get{3}(MlirOperation op) {{
609 return mlirOperationGetAttributeByName(op, mlirStringRefCreateFromCString("{4}"));
610}
611)";
612 assert(!className.empty() && "className must be set");
613 assert(!attrNameCapitalized.empty() && "attrName must be set");
614 os << llvm::formatv(
615 fmt,
616 getFunctionPrefix(), // {0}
618 className, // {2}
619 attrNameCapitalized, // {3}
620 attrName // {4}
621 );
622 }
623
624 void genAttributeSetterImpl(mlir::StringRef attrName) const {
625 static constexpr char fmt[] = R"(
626void {0}{1}_{2}Set{3}(MlirOperation op, MlirAttribute attr) {{
627 mlirOperationSetAttributeByName(op, mlirStringRefCreateFromCString("{4}"), attr);
628}
629)";
630 assert(!className.empty() && "className must be set");
631 assert(!attrNameCapitalized.empty() && "attrName must be set");
632 os << llvm::formatv(
633 fmt,
634 getFunctionPrefix(), // {0}
636 className, // {2}
637 attrNameCapitalized, // {3}
638 attrName // {4}
639 );
640 }
641
642 void genResultGetterImpl(int index) const {
643 static constexpr char fmt[] = R"(
644MlirValue {0}{1}_{2}Get{3}(MlirOperation op) {{
645 return mlirOperationGetResult(op, {4});
646}
647)";
648 assert(!className.empty() && "className must be set");
649 assert(!resultNameCapitalized.empty() && "resultName must be set");
650 os << llvm::formatv(
651 fmt,
652 getFunctionPrefix(), // {0}
654 className, // {2}
656 index // {4}
657 );
658 }
659
660 void genVariadicResultGetterImpl(int startIdx) const {
661 static constexpr char fmt[] = R"(
662intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op) {{
663 intptr_t count = mlirOperationGetNumResults(op);
664 assert(count >= {4} && "result count less than start index");
665 return count - {4};
666}
667
668MlirValue {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index) {{
669 return mlirOperationGetResult(op, {4} + index);
670}
671)";
672 assert(!className.empty() && "className must be set");
673 assert(!resultNameCapitalized.empty() && "resultName must be set");
674 os << llvm::formatv(
675 fmt,
676 getFunctionPrefix(), // {0}
678 className, // {2}
680 startIdx // {4}
681 );
682 }
683
684 void genRegionGetterImpl(unsigned index) const {
685 static constexpr char fmt[] = R"(
686MlirRegion {0}{1}_{2}Get{3}(MlirOperation op) {{
687 return mlirOperationGetRegion(op, {4});
688}
689)";
690 assert(!className.empty() && "className must be set");
691 assert(!regionNameCapitalized.empty() && "regionName must be set");
692 os << llvm::formatv(
693 fmt,
694 getFunctionPrefix(), // {0}
696 className, // {2}
698 index // {4}
699 );
700 }
701
702 void genVariadicRegionGetterImpl(unsigned startIdx) const {
703 static constexpr char fmt[] = R"(
704intptr_t {0}{1}_{2}Get{3}Count(MlirOperation op) {{
705 intptr_t count = mlirOperationGetNumRegions(op);
706 assert(count >= {4} && "region count less than start index");
707 return count - {4};
708}
709
710MlirRegion {0}{1}_{2}Get{3}At(MlirOperation op, intptr_t index) {{
711 return mlirOperationGetRegion(op, {4} + index);
712}
713)";
714 assert(!className.empty() && "className must be set");
715 assert(!regionNameCapitalized.empty() && "regionName must be set");
716 os << llvm::formatv(
717 fmt,
718 getFunctionPrefix(), // {0}
720 className, // {2}
722 startIdx // {4}
723 );
724 }
725};
726
732static std::string generateCAPIAssignments(const Operator &op) {
733 // Code generated here can use the following variables:
734 // - MlirOpBuilder builder
735 // - MlirLocation location
736 // - MlirOperationState state
737 // - Operand/Attribute/Result parameters per `generateCAPIBuildParams()`
738 struct : GenStringFromOpPieces {
739 void genResultInferred(llvm::raw_ostream &os) override {
740 os << " mlirOperationStateEnableResultTypeInference(&state);\n";
741 }
742 void genResult(
743 llvm::raw_ostream &os, const NamedTypeConstraint &result, const std::string &resultName
744 ) override {
745 if (result.isVariadic()) {
746 os << llvm::formatv(
747 " mlirOperationStateAddResults(&state, {0}Size, {0}Types);\n", resultName
748 );
749 } else {
750 os << llvm::formatv(" mlirOperationStateAddResults(&state, 1, &{0}Type);\n", resultName);
751 }
752 }
753 void genOperand(llvm::raw_ostream &os, const NamedTypeConstraint &operand) override {
754 if (operand.isVariadic()) {
755 os << llvm::formatv(
756 " mlirOperationStateAddOperands(&state, {0}Size, {0});\n", operand.name
757 );
758 } else {
759 os << llvm::formatv(" mlirOperationStateAddOperands(&state, 1, &{0});\n", operand.name);
760 }
761 }
762 void genAttributesPrefix(llvm::raw_ostream &os, const mlir::tblgen::Operator &op) override {
763 os << " MlirContext ctx = mlirOpBuilderGetContext(builder);\n";
764 os << " llvm::SmallVector<MlirNamedAttribute, " << op.getNumAttributes()
765 << "> attributes;\n";
766 }
767 void genAttribute(llvm::raw_ostream &os, const NamedAttribute &attr) override {
768 // The second parameter to `mlirNamedAttributeGet()` must be an "MlirAttribute". However, if
769 // it ends up as "MlirIdentifier", a reinterpret cast is needed. These C structs have the same
770 // layout and the C++ mlir::StringAttr is a subclass of mlir::Attribute so the cast is safe.
771 std::optional<std::string> attrType = tryCppTypeToCapiType(attr.attr.getStorageType());
772 std::string attrValue;
773 if (attrType.has_value() && attrType.value() == "MlirIdentifier") {
774 attrValue = "reinterpret_cast<MlirAttribute&>(" + attr.name.str() + ")";
775 } else {
776 attrValue = attr.name.str();
777 }
778
779 os << " if (!mlirAttributeIsNull(" << attrValue << ")) {\n";
780 os << " attributes.push_back(mlirNamedAttributeGet(mlirIdentifierGet(ctx, "
781 << "mlirStringRefCreateFromCString(\"" << attr.name << "\")), " << attrValue << "));\n";
782 os << " }\n";
783 }
784 void
785 genAttributesSuffix(llvm::raw_ostream &os, const mlir::tblgen::Operator & /*op*/) override {
786 os << " mlirOperationStateAddAttributes(&state, attributes.size(), attributes.data());\n";
787 }
788 void genRegionsPrefix(llvm::raw_ostream &os, const mlir::tblgen::Operator &op) override {
789 os << " llvm::SmallVector<MlirRegion, " << op.getNumRegions() << "> regions;\n";
790 }
791 void genRegion(llvm::raw_ostream &os, const mlir::tblgen::NamedRegion &region) override {
792 if (region.isVariadic()) {
793 os << llvm::formatv(" for (unsigned i = 0; i < {0}Count; ++i)\n ", region.name);
794 }
795 os << " regions.push_back(mlirRegionCreate());\n";
796 }
797 void genRegionsSuffix(llvm::raw_ostream &os, const mlir::tblgen::Operator & /*op*/) override {
798 os << " mlirOperationStateAddOwnedRegions(&state, regions.size(), regions.data());\n";
799 }
800 } paramStringGenerator;
801 return paramStringGenerator.gen(op);
802}
803
805static bool emitOpCAPIImpl(const llvm::RecordKeeper &records, raw_ostream &os) {
806 emitSourceFileHeader("Op C API Definitions", os, records);
807
808 OpImplementationGenerator generator("Operation", os);
809 generator.genPrologue();
810
811 for (const auto *def : records.getAllDerivedDefinitions("Op")) {
812 const Operator op(def);
813 const Dialect &dialect = op.getDialect();
814
815 // Generate for the selected dialect only (specified via -dialect command-line option)
816 if (dialect.getName() != getDialectName()) {
817 continue;
818 }
819
820 generator.setNamespaceAndClassName(dialect, op.getCppClassName());
821
822 // Generate "Build" function
823 if (getGenOpBuild() && !op.skipDefaultBuilders()) {
824 std::string assignments = generateCAPIAssignments(op);
825 generator.genOpBuildImpl(op.getOperationName(), generateCAPIBuildParams(op), assignments);
826 }
827
828 // Generate IsA check implementation
829 if (getGenIsA()) {
830 generator.genIsAImpl();
831 }
832
833 // Generate operand getters and setters
834 for (int i = 0, e = op.getNumOperands(); i < e; ++i) {
835 const auto &operand = op.getOperand(i);
836 generator.setOperandName(operand.name);
837 if (operand.isVariadic()) {
839 generator.genVariadicOperandGetterImpl(i);
840 }
842 if (operand.isVariadicOfVariadic()) {
843 generator.genVariadicOfVariadicOperandSetterImpl(
844 operand.constraint.getVariadicOfVariadicSegmentSizeAttr()
845 );
846 } else {
847 generator.genVariadicOperandSetterImpl();
848 }
849 }
850 } else {
852 generator.genOperandGetterImpl(i);
853 }
855 generator.genOperandSetterImpl(i);
856 }
857 }
858 }
859
860 // Generate attribute getters and setters
861 for (const auto &namedAttr : op.getAttributes()) {
862 generator.setAttributeName(namedAttr.name);
864 generator.genAttributeGetterImpl(namedAttr.name);
865 }
867 generator.genAttributeSetterImpl(namedAttr.name);
868 }
869 }
870
871 // Generate result getters
872 if (getGenOpResultGetters()) {
873 for (int i = 0, e = op.getNumResults(); i < e; ++i) {
874 const auto &result = op.getResult(i);
875 generator.setResultName(result.name, i);
876 if (result.isVariadic()) {
877 generator.genVariadicResultGetterImpl(i);
878 } else {
879 generator.genResultGetterImpl(i);
880 }
881 }
882 }
883
884 // Generate region getters
885 if (getGenOpRegionGetters()) {
886 for (unsigned i = 0, e = op.getNumRegions(); i < e; ++i) {
887 const auto &region = op.getRegion(i);
888 generator.setRegionName(region.name, i);
889 if (region.isVariadic()) {
890 generator.genVariadicRegionGetterImpl(i);
891 } else {
892 generator.genRegionGetterImpl(i);
893 }
894 }
895 }
896
897 // Generate implementations for interface and extra class methods.
899 for (const ExtraMethod &method : getCAPIExposedOpMethods(op)) {
900 generator.genExtraMethod(method);
901 }
902 }
903 }
904
905 return false;
906}
907
909 static mlir::GenRegistration genOpCAPIHeader(
910 "gen-op-capi-header", "Generate operation C API header", &emitOpCAPIHeader
911 );
912
913 static mlir::GenRegistration genOpCAPIImpl(
914 "gen-op-capi-impl", "Generate operation C API implementation", &emitOpCAPIImpl
915 );
916}
llvm::cl::opt< bool > & getGenOpOperandGetters()
Return the GenOpOperandGetters option, registering it on first access.
std::optional< std::string > tryCppTypeToCapiType(StringRef cppType)
Convert C++ type to MLIR C API type.
llvm::cl::opt< std::string > & getFunctionPrefix()
Return the FunctionPrefix option, registering it on first access.
llvm::cl::opt< bool > & getGenOpRegionGetters()
Return the GenOpRegionGetters option, registering it on first access.
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.
llvm::cl::opt< bool > & getGenOpAttributeSetters()
Return the GenOpAttributeSetters option, registering it on first access.
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::cl::opt< bool > & getGenExtraClassMethods()
Return the GenExtraClassMethods 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::SmallVector< ExtraMethod > getCAPIExposedOpMethods(const mlir::tblgen::Operator &op)
Return public operation methods explicitly requested by DeclareOpInterfaceMethods traits and declared...
std::string toPascalCase(mlir::StringRef str)
Convert names separated by underscore or colon to PascalCase.
void registerOpCAPIGenerators()
Register the operation C API generators before command-line parsing.
Structure to represent a parsed method signature from an extraClassDeclaration.
Helper struct to generate a string from operation operand, attribute, and result pieces.
mlir::StringRef className
mlir::StringRef dialectNamespace
std::string dialectNameCapitalized
llvm::raw_ostream & os
Generator for common C header file elements.
Generator for common C implementation file elements.
Common between header and implementation generators for operations.
Definition OpCAPIGen.cpp:34
void setAttributeName(mlir::StringRef name)
Definition OpCAPIGen.cpp:36
void setResultName(mlir::StringRef name, int resultIndex)
Definition OpCAPIGen.cpp:37
void setOperandName(mlir::StringRef name)
Definition OpCAPIGen.cpp:35
std::string resultNameCapitalized
Definition OpCAPIGen.cpp:49
std::string attrNameCapitalized
Definition OpCAPIGen.cpp:48
std::string operandNameCapitalized
Definition OpCAPIGen.cpp:47
void setRegionName(mlir::StringRef name, unsigned regionIndex)
Definition OpCAPIGen.cpp:41
std::string regionNameCapitalized
Definition OpCAPIGen.cpp:50
Generator for operation C header files.
Definition OpCAPIGen.cpp:54
void genVariadicRegionGetterDecl() const
void genVariadicOfVariadicOperandSetterDecl() const
void genVariadicResultGetterDecl() const
~OpHeaderGenerator() override=default
void genOperandSetterDecl() const
Definition OpCAPIGen.cpp:85
void genVariadicOperandSetterDecl() const
void genAttributeGetterDecl() const
void genRegionGetterDecl() const
void genAttributeSetterDecl() const
void genVariadicOperandGetterDecl() const
Definition OpCAPIGen.cpp:99
void genResultGetterDecl() const
void genOpBuildDecl(const std::string &params) const
Definition OpCAPIGen.cpp:58
void genOperandGetterDecl() const
Definition OpCAPIGen.cpp:71
Generator for operation C implementation files.
void genOperandGetterImpl(int index) const
void genRegionGetterImpl(unsigned index) const
void genAttributeGetterImpl(mlir::StringRef attrName) const
void genVariadicRegionGetterImpl(unsigned startIdx) const
void genVariadicResultGetterImpl(int startIdx) const
void genVariadicOfVariadicOperandSetterImpl(mlir::StringRef segSizeAttrName) const
void genOpBuildImpl(const std::string &operationName, const std::string &params, const std::string &assignments) const
Generate operation "Build" function implementation.
void genResultGetterImpl(int index) const
~OpImplementationGenerator() override=default
void genOperandSetterImpl(int index) const
void genVariadicOperandGetterImpl(int index) const
void genPrologue() const override
void genAttributeSetterImpl(mlir::StringRef attrName) const
void genVariadicOperandSetterImpl() const