xref: /llvm-project/mlir/test/lib/Dialect/Test/TestAttributes.cpp (revision 690dc4eff19c85d0afaa9e189cf7e40fe3d1ff76)
183ef862fSRiver Riddle //===- TestAttributes.cpp - MLIR Test Dialect Attributes --------*- C++ -*-===//
283ef862fSRiver Riddle //
383ef862fSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
483ef862fSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
583ef862fSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
683ef862fSRiver Riddle //
783ef862fSRiver Riddle //===----------------------------------------------------------------------===//
883ef862fSRiver Riddle //
983ef862fSRiver Riddle // This file contains attributes defined by the TestDialect for testing various
1083ef862fSRiver Riddle // features of MLIR.
1183ef862fSRiver Riddle //
1283ef862fSRiver Riddle //===----------------------------------------------------------------------===//
1383ef862fSRiver Riddle 
1483ef862fSRiver Riddle #include "TestAttributes.h"
1583ef862fSRiver Riddle #include "TestDialect.h"
16*690dc4efSquartersdg #include "TestTypes.h"
17*690dc4efSquartersdg #include "mlir/IR/Attributes.h"
1883ef862fSRiver Riddle #include "mlir/IR/Builders.h"
1983ef862fSRiver Riddle #include "mlir/IR/DialectImplementation.h"
209e0b5533SMathieu Fehr #include "mlir/IR/ExtensibleDialect.h"
21*690dc4efSquartersdg #include "mlir/IR/OpImplementation.h"
2283ef862fSRiver Riddle #include "mlir/IR/Types.h"
231e3c630fSorbiri #include "llvm/ADT/APFloat.h"
2483ef862fSRiver Riddle #include "llvm/ADT/Hashing.h"
25e95e94adSJeff Niu #include "llvm/ADT/StringExtras.h"
2683ef862fSRiver Riddle #include "llvm/ADT/TypeSwitch.h"
279a2fdc36SJeff Niu #include "llvm/ADT/bit.h"
289e0b5533SMathieu Fehr #include "llvm/Support/ErrorHandling.h"
295fc28e7aSMehdi Amini #include "llvm/Support/raw_ostream.h"
3083ef862fSRiver Riddle 
3183ef862fSRiver Riddle using namespace mlir;
327776b19eSStephen Neuendorffer using namespace test;
3383ef862fSRiver Riddle 
341447ec51SRiver Riddle //===----------------------------------------------------------------------===//
351447ec51SRiver Riddle // CompoundAAttr
361447ec51SRiver Riddle //===----------------------------------------------------------------------===//
371447ec51SRiver Riddle 
38f97e72aaSMehdi Amini Attribute CompoundAAttr::parse(AsmParser &parser, Type type) {
3983ef862fSRiver Riddle   int widthOfSomething;
4083ef862fSRiver Riddle   Type oneType;
4183ef862fSRiver Riddle   SmallVector<int, 4> arrayOfInts;
4283ef862fSRiver Riddle   if (parser.parseLess() || parser.parseInteger(widthOfSomething) ||
4383ef862fSRiver Riddle       parser.parseComma() || parser.parseType(oneType) || parser.parseComma() ||
4483ef862fSRiver Riddle       parser.parseLSquare())
4583ef862fSRiver Riddle     return Attribute();
4683ef862fSRiver Riddle 
4783ef862fSRiver Riddle   int intVal;
4883ef862fSRiver Riddle   while (!*parser.parseOptionalInteger(intVal)) {
4983ef862fSRiver Riddle     arrayOfInts.push_back(intVal);
5083ef862fSRiver Riddle     if (parser.parseOptionalComma())
5183ef862fSRiver Riddle       break;
5283ef862fSRiver Riddle   }
5383ef862fSRiver Riddle 
5483ef862fSRiver Riddle   if (parser.parseRSquare() || parser.parseGreater())
5583ef862fSRiver Riddle     return Attribute();
56fb093c83SChris Lattner   return get(parser.getContext(), widthOfSomething, oneType, arrayOfInts);
5783ef862fSRiver Riddle }
5883ef862fSRiver Riddle 
59f97e72aaSMehdi Amini void CompoundAAttr::print(AsmPrinter &printer) const {
60f30a8a6fSMehdi Amini   printer << "<" << getWidthOfSomething() << ", " << getOneType() << ", [";
6183ef862fSRiver Riddle   llvm::interleaveComma(getArrayOfInts(), printer);
6283ef862fSRiver Riddle   printer << "]>";
6383ef862fSRiver Riddle }
6483ef862fSRiver Riddle 
6583ef862fSRiver Riddle //===----------------------------------------------------------------------===//
66d80d3a35SRiver Riddle // CompoundAAttr
67d80d3a35SRiver Riddle //===----------------------------------------------------------------------===//
68d80d3a35SRiver Riddle 
69*690dc4efSquartersdg Attribute TestDecimalShapeAttr::parse(AsmParser &parser, Type type) {
70*690dc4efSquartersdg   if (parser.parseLess()){
71*690dc4efSquartersdg     return Attribute();
72*690dc4efSquartersdg   }
73*690dc4efSquartersdg   SmallVector<int64_t> shape;
74*690dc4efSquartersdg   if (parser.parseOptionalGreater()) {
75*690dc4efSquartersdg     auto parseDecimal = [&]() {
76*690dc4efSquartersdg       shape.emplace_back();
77*690dc4efSquartersdg       auto parseResult = parser.parseOptionalDecimalInteger(shape.back());
78*690dc4efSquartersdg       if (!parseResult.has_value() || failed(*parseResult)) {
79*690dc4efSquartersdg         parser.emitError(parser.getCurrentLocation()) << "expected an integer";
80*690dc4efSquartersdg         return failure();
81*690dc4efSquartersdg       }
82*690dc4efSquartersdg       return success();
83*690dc4efSquartersdg     };
84*690dc4efSquartersdg     if (failed(parseDecimal())) {
85*690dc4efSquartersdg       return Attribute();
86*690dc4efSquartersdg     }
87*690dc4efSquartersdg     while (failed(parser.parseOptionalGreater())) {
88*690dc4efSquartersdg       if (failed(parser.parseXInDimensionList()) || failed(parseDecimal())) {
89*690dc4efSquartersdg         return Attribute();
90*690dc4efSquartersdg       }
91*690dc4efSquartersdg     }
92*690dc4efSquartersdg   }
93*690dc4efSquartersdg   return get(parser.getContext(), shape);
94*690dc4efSquartersdg }
95*690dc4efSquartersdg 
96*690dc4efSquartersdg void TestDecimalShapeAttr::print(AsmPrinter &printer) const {
97*690dc4efSquartersdg   printer << "<";
98*690dc4efSquartersdg   llvm::interleave(getShape(), printer, "x");
99*690dc4efSquartersdg   printer << ">";
100*690dc4efSquartersdg }
101*690dc4efSquartersdg 
102f97e72aaSMehdi Amini Attribute TestI64ElementsAttr::parse(AsmParser &parser, Type type) {
103d80d3a35SRiver Riddle   SmallVector<uint64_t> elements;
104d80d3a35SRiver Riddle   if (parser.parseLess() || parser.parseLSquare())
105d80d3a35SRiver Riddle     return Attribute();
106d80d3a35SRiver Riddle   uint64_t intVal;
107d80d3a35SRiver Riddle   while (succeeded(*parser.parseOptionalInteger(intVal))) {
108d80d3a35SRiver Riddle     elements.push_back(intVal);
109d80d3a35SRiver Riddle     if (parser.parseOptionalComma())
110d80d3a35SRiver Riddle       break;
111d80d3a35SRiver Riddle   }
112d80d3a35SRiver Riddle 
113d80d3a35SRiver Riddle   if (parser.parseRSquare() || parser.parseGreater())
114d80d3a35SRiver Riddle     return Attribute();
115d80d3a35SRiver Riddle   return parser.getChecked<TestI64ElementsAttr>(
116c1fa60b4STres Popp       parser.getContext(), llvm::cast<ShapedType>(type), elements);
117d80d3a35SRiver Riddle }
118d80d3a35SRiver Riddle 
119f97e72aaSMehdi Amini void TestI64ElementsAttr::print(AsmPrinter &printer) const {
120f30a8a6fSMehdi Amini   printer << "<[";
121d80d3a35SRiver Riddle   llvm::interleaveComma(getElements(), printer);
122bc6b5be6SMatteo Franciolini   printer << "]>";
123d80d3a35SRiver Riddle }
124d80d3a35SRiver Riddle 
125d80d3a35SRiver Riddle LogicalResult
126d80d3a35SRiver Riddle TestI64ElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,
127d80d3a35SRiver Riddle                             ShapedType type, ArrayRef<uint64_t> elements) {
128d80d3a35SRiver Riddle   if (type.getNumElements() != static_cast<int64_t>(elements.size())) {
129d80d3a35SRiver Riddle     return emitError()
130d80d3a35SRiver Riddle            << "number of elements does not match the provided shape type, got: "
131d80d3a35SRiver Riddle            << elements.size() << ", but expected: " << type.getNumElements();
132d80d3a35SRiver Riddle   }
133d80d3a35SRiver Riddle   if (type.getRank() != 1 || !type.getElementType().isSignlessInteger(64))
134d80d3a35SRiver Riddle     return emitError() << "expected single rank 64-bit shape type, but got: "
135d80d3a35SRiver Riddle                        << type;
136d80d3a35SRiver Riddle   return success();
137d80d3a35SRiver Riddle }
138d80d3a35SRiver Riddle 
139a71bc5f5Srkayaith LogicalResult TestAttrWithFormatAttr::verify(
140a71bc5f5Srkayaith     function_ref<InFlightDiagnostic()> emitError, int64_t one, std::string two,
141a71bc5f5Srkayaith     IntegerAttr three, ArrayRef<int> four, uint64_t five, ArrayRef<int> six,
142e1795322SJeff Niu     ArrayRef<AttrWithTypeBuilderAttr> arrayOfAttrs) {
1439a2fdc36SJeff Niu   if (four.size() != static_cast<unsigned>(one))
1449a2fdc36SJeff Niu     return emitError() << "expected 'one' to equal 'four.size()'";
1459a2fdc36SJeff Niu   return success();
1469a2fdc36SJeff Niu }
1479a2fdc36SJeff Niu 
1489a2fdc36SJeff Niu //===----------------------------------------------------------------------===//
1499a2fdc36SJeff Niu // Utility Functions for Generated Attributes
1509a2fdc36SJeff Niu //===----------------------------------------------------------------------===//
1519a2fdc36SJeff Niu 
152f97e72aaSMehdi Amini static FailureOr<SmallVector<int>> parseIntArray(AsmParser &parser) {
1539a2fdc36SJeff Niu   SmallVector<int> ints;
1549a2fdc36SJeff Niu   if (parser.parseLSquare() || parser.parseCommaSeparatedList([&]() {
1559a2fdc36SJeff Niu         ints.push_back(0);
1569a2fdc36SJeff Niu         return parser.parseInteger(ints.back());
1579a2fdc36SJeff Niu       }) ||
1589a2fdc36SJeff Niu       parser.parseRSquare())
1599a2fdc36SJeff Niu     return failure();
1609a2fdc36SJeff Niu   return ints;
1619a2fdc36SJeff Niu }
1629a2fdc36SJeff Niu 
163f97e72aaSMehdi Amini static void printIntArray(AsmPrinter &printer, ArrayRef<int> ints) {
1649a2fdc36SJeff Niu   printer << '[';
1659a2fdc36SJeff Niu   llvm::interleaveComma(ints, printer);
1669a2fdc36SJeff Niu   printer << ']';
1679a2fdc36SJeff Niu }
1689a2fdc36SJeff Niu 
169d80d3a35SRiver Riddle //===----------------------------------------------------------------------===//
17010a80c44SMarkus Böck // TestSubElementsAccessAttr
17110a80c44SMarkus Böck //===----------------------------------------------------------------------===//
17210a80c44SMarkus Böck 
173f97e72aaSMehdi Amini Attribute TestSubElementsAccessAttr::parse(::mlir::AsmParser &parser,
17410a80c44SMarkus Böck                                            ::mlir::Type type) {
17510a80c44SMarkus Böck   Attribute first, second, third;
17610a80c44SMarkus Böck   if (parser.parseLess() || parser.parseAttribute(first) ||
17710a80c44SMarkus Böck       parser.parseComma() || parser.parseAttribute(second) ||
17810a80c44SMarkus Böck       parser.parseComma() || parser.parseAttribute(third) ||
17910a80c44SMarkus Böck       parser.parseGreater()) {
18010a80c44SMarkus Böck     return {};
18110a80c44SMarkus Böck   }
18210a80c44SMarkus Böck   return get(parser.getContext(), first, second, third);
18310a80c44SMarkus Böck }
18410a80c44SMarkus Böck 
185f97e72aaSMehdi Amini void TestSubElementsAccessAttr::print(::mlir::AsmPrinter &printer) const {
186f30a8a6fSMehdi Amini   printer << "<" << getFirst() << ", " << getSecond() << ", " << getThird()
187f30a8a6fSMehdi Amini           << ">";
18810a80c44SMarkus Böck }
18910a80c44SMarkus Böck 
19010a80c44SMarkus Böck //===----------------------------------------------------------------------===//
191ea488bd6SRiver Riddle // TestExtern1DI64ElementsAttr
192ea488bd6SRiver Riddle //===----------------------------------------------------------------------===//
193ea488bd6SRiver Riddle 
194ea488bd6SRiver Riddle ArrayRef<uint64_t> TestExtern1DI64ElementsAttr::getElements() const {
1955f58e14bSRiver Riddle   if (auto *blob = getHandle().getBlob())
1965f58e14bSRiver Riddle     return blob->getDataAs<uint64_t>();
1971a36588eSKazu Hirata   return std::nullopt;
198ea488bd6SRiver Riddle }
199ea488bd6SRiver Riddle 
200ea488bd6SRiver Riddle //===----------------------------------------------------------------------===//
201e936c3bbSJeff Niu // TestCustomAnchorAttr
202e936c3bbSJeff Niu //===----------------------------------------------------------------------===//
203e936c3bbSJeff Niu 
204715b0258SMarkus Böck static ParseResult parseTrueFalse(AsmParser &p, std::optional<int> &result) {
205e936c3bbSJeff Niu   bool b;
206e936c3bbSJeff Niu   if (p.parseInteger(b))
207e936c3bbSJeff Niu     return failure();
208715b0258SMarkus Böck   result = b;
209e936c3bbSJeff Niu   return success();
210e936c3bbSJeff Niu }
211e936c3bbSJeff Niu 
212e8bcc37fSRamkumar Ramachandra static void printTrueFalse(AsmPrinter &p, std::optional<int> result) {
213e936c3bbSJeff Niu   p << (*result ? "true" : "false");
214e936c3bbSJeff Niu }
215e936c3bbSJeff Niu 
216e936c3bbSJeff Niu //===----------------------------------------------------------------------===//
2175fc28e7aSMehdi Amini // CopyCountAttr Implementation
2185fc28e7aSMehdi Amini //===----------------------------------------------------------------------===//
2195fc28e7aSMehdi Amini 
2205fc28e7aSMehdi Amini CopyCount::CopyCount(const CopyCount &rhs) : value(rhs.value) {
2215fc28e7aSMehdi Amini   CopyCount::counter++;
2225fc28e7aSMehdi Amini }
2235fc28e7aSMehdi Amini 
2245fc28e7aSMehdi Amini CopyCount &CopyCount::operator=(const CopyCount &rhs) {
2255fc28e7aSMehdi Amini   CopyCount::counter++;
2265fc28e7aSMehdi Amini   value = rhs.value;
2275fc28e7aSMehdi Amini   return *this;
2285fc28e7aSMehdi Amini }
2295fc28e7aSMehdi Amini 
2305fc28e7aSMehdi Amini int CopyCount::counter;
2315fc28e7aSMehdi Amini 
2325fc28e7aSMehdi Amini static bool operator==(const test::CopyCount &lhs, const test::CopyCount &rhs) {
2335fc28e7aSMehdi Amini   return lhs.value == rhs.value;
2345fc28e7aSMehdi Amini }
2355fc28e7aSMehdi Amini 
2365fc28e7aSMehdi Amini llvm::raw_ostream &test::operator<<(llvm::raw_ostream &os,
2375fc28e7aSMehdi Amini                                     const test::CopyCount &value) {
2385fc28e7aSMehdi Amini   return os << value.value;
2395fc28e7aSMehdi Amini }
2405fc28e7aSMehdi Amini 
2415fc28e7aSMehdi Amini template <>
2425fc28e7aSMehdi Amini struct mlir::FieldParser<test::CopyCount> {
2435fc28e7aSMehdi Amini   static FailureOr<test::CopyCount> parse(AsmParser &parser) {
2445fc28e7aSMehdi Amini     std::string value;
2455fc28e7aSMehdi Amini     if (parser.parseKeyword(value))
2465fc28e7aSMehdi Amini       return failure();
2475fc28e7aSMehdi Amini     return test::CopyCount(value);
2485fc28e7aSMehdi Amini   }
2495fc28e7aSMehdi Amini };
2505fc28e7aSMehdi Amini namespace test {
2515fc28e7aSMehdi Amini llvm::hash_code hash_value(const test::CopyCount &copyCount) {
2525fc28e7aSMehdi Amini   return llvm::hash_value(copyCount.value);
2535fc28e7aSMehdi Amini }
2545fc28e7aSMehdi Amini } // namespace test
255df1e01b3SJeff Niu 
256df1e01b3SJeff Niu //===----------------------------------------------------------------------===//
257df1e01b3SJeff Niu // TestConditionalAliasAttr
258df1e01b3SJeff Niu //===----------------------------------------------------------------------===//
259df1e01b3SJeff Niu 
260df1e01b3SJeff Niu /// Attempt to parse the conditionally-aliased string attribute as a keyword or
261df1e01b3SJeff Niu /// string, else try to parse an alias.
262df1e01b3SJeff Niu static ParseResult parseConditionalAlias(AsmParser &p, StringAttr &value) {
263df1e01b3SJeff Niu   std::string str;
264df1e01b3SJeff Niu   if (succeeded(p.parseOptionalKeywordOrString(&str))) {
265df1e01b3SJeff Niu     value = StringAttr::get(p.getContext(), str);
266df1e01b3SJeff Niu     return success();
267df1e01b3SJeff Niu   }
268df1e01b3SJeff Niu   return p.parseAttribute(value);
269df1e01b3SJeff Niu }
270df1e01b3SJeff Niu 
271df1e01b3SJeff Niu /// Print the string attribute as an alias if it has one, otherwise print it as
272df1e01b3SJeff Niu /// a keyword if possible.
273df1e01b3SJeff Niu static void printConditionalAlias(AsmPrinter &p, StringAttr value) {
274df1e01b3SJeff Niu   if (succeeded(p.printAlias(value)))
275df1e01b3SJeff Niu     return;
276df1e01b3SJeff Niu   p.printKeywordOrString(value);
277df1e01b3SJeff Niu }
278df1e01b3SJeff Niu 
2795fc28e7aSMehdi Amini //===----------------------------------------------------------------------===//
2801e3c630fSorbiri // Custom Float Attribute
2811e3c630fSorbiri //===----------------------------------------------------------------------===//
2821e3c630fSorbiri 
2831e3c630fSorbiri static void printCustomFloatAttr(AsmPrinter &p, StringAttr typeStrAttr,
2841e3c630fSorbiri                                  APFloat value) {
2851e3c630fSorbiri   p << typeStrAttr << " : " << value;
2861e3c630fSorbiri }
2871e3c630fSorbiri 
2881e3c630fSorbiri static ParseResult parseCustomFloatAttr(AsmParser &p, StringAttr &typeStrAttr,
2891e3c630fSorbiri                                         FailureOr<APFloat> &value) {
2901e3c630fSorbiri 
2911e3c630fSorbiri   std::string str;
2921e3c630fSorbiri   if (p.parseString(&str))
2931e3c630fSorbiri     return failure();
2941e3c630fSorbiri 
2951e3c630fSorbiri   typeStrAttr = StringAttr::get(p.getContext(), str);
2961e3c630fSorbiri 
2971e3c630fSorbiri   if (p.parseColon())
2981e3c630fSorbiri     return failure();
2991e3c630fSorbiri 
3001e3c630fSorbiri   const llvm::fltSemantics *semantics;
3011e3c630fSorbiri   if (str == "float")
3021e3c630fSorbiri     semantics = &llvm::APFloat::IEEEsingle();
3031e3c630fSorbiri   else if (str == "double")
3041e3c630fSorbiri     semantics = &llvm::APFloat::IEEEdouble();
3051e3c630fSorbiri   else if (str == "fp80")
3061e3c630fSorbiri     semantics = &llvm::APFloat::x87DoubleExtended();
3071e3c630fSorbiri   else
3081e3c630fSorbiri     return p.emitError(p.getCurrentLocation(), "unknown float type, expected "
3091e3c630fSorbiri                                                "'float', 'double' or 'fp80'");
3101e3c630fSorbiri 
3111e3c630fSorbiri   APFloat parsedValue(0.0);
3121e3c630fSorbiri   if (p.parseFloat(*semantics, parsedValue))
3131e3c630fSorbiri     return failure();
3141e3c630fSorbiri 
3151e3c630fSorbiri   value.emplace(parsedValue);
3161e3c630fSorbiri   return success();
3171e3c630fSorbiri }
3181e3c630fSorbiri 
3191e3c630fSorbiri //===----------------------------------------------------------------------===//
32083ef862fSRiver Riddle // Tablegen Generated Definitions
32183ef862fSRiver Riddle //===----------------------------------------------------------------------===//
32283ef862fSRiver Riddle 
3239b2a1bcfSAlex Zinenko #include "TestAttrInterfaces.cpp.inc"
324e95e94adSJeff Niu #include "TestOpEnums.cpp.inc"
32583ef862fSRiver Riddle #define GET_ATTRDEF_CLASSES
32683ef862fSRiver Riddle #include "TestAttrDefs.cpp.inc"
32783ef862fSRiver Riddle 
32883ef862fSRiver Riddle //===----------------------------------------------------------------------===//
3299e0b5533SMathieu Fehr // Dynamic Attributes
3309e0b5533SMathieu Fehr //===----------------------------------------------------------------------===//
3319e0b5533SMathieu Fehr 
3329e0b5533SMathieu Fehr /// Define a singleton dynamic attribute.
3339e0b5533SMathieu Fehr static std::unique_ptr<DynamicAttrDefinition>
3349e0b5533SMathieu Fehr getDynamicSingletonAttr(TestDialect *testDialect) {
3359e0b5533SMathieu Fehr   return DynamicAttrDefinition::get(
3369e0b5533SMathieu Fehr       "dynamic_singleton", testDialect,
3379e0b5533SMathieu Fehr       [](function_ref<InFlightDiagnostic()> emitError,
3389e0b5533SMathieu Fehr          ArrayRef<Attribute> args) {
3399e0b5533SMathieu Fehr         if (!args.empty()) {
3409e0b5533SMathieu Fehr           emitError() << "expected 0 attribute arguments, but had "
3419e0b5533SMathieu Fehr                       << args.size();
3429e0b5533SMathieu Fehr           return failure();
3439e0b5533SMathieu Fehr         }
3449e0b5533SMathieu Fehr         return success();
3459e0b5533SMathieu Fehr       });
3469e0b5533SMathieu Fehr }
3479e0b5533SMathieu Fehr 
3489e0b5533SMathieu Fehr /// Define a dynamic attribute representing a pair or attributes.
3499e0b5533SMathieu Fehr static std::unique_ptr<DynamicAttrDefinition>
3509e0b5533SMathieu Fehr getDynamicPairAttr(TestDialect *testDialect) {
3519e0b5533SMathieu Fehr   return DynamicAttrDefinition::get(
3529e0b5533SMathieu Fehr       "dynamic_pair", testDialect,
3539e0b5533SMathieu Fehr       [](function_ref<InFlightDiagnostic()> emitError,
3549e0b5533SMathieu Fehr          ArrayRef<Attribute> args) {
3559e0b5533SMathieu Fehr         if (args.size() != 2) {
3569e0b5533SMathieu Fehr           emitError() << "expected 2 attribute arguments, but had "
3579e0b5533SMathieu Fehr                       << args.size();
3589e0b5533SMathieu Fehr           return failure();
3599e0b5533SMathieu Fehr         }
3609e0b5533SMathieu Fehr         return success();
3619e0b5533SMathieu Fehr       });
3629e0b5533SMathieu Fehr }
3639e0b5533SMathieu Fehr 
3649e0b5533SMathieu Fehr static std::unique_ptr<DynamicAttrDefinition>
3659e0b5533SMathieu Fehr getDynamicCustomAssemblyFormatAttr(TestDialect *testDialect) {
3669e0b5533SMathieu Fehr   auto verifier = [](function_ref<InFlightDiagnostic()> emitError,
3679e0b5533SMathieu Fehr                      ArrayRef<Attribute> args) {
3689e0b5533SMathieu Fehr     if (args.size() != 2) {
3699e0b5533SMathieu Fehr       emitError() << "expected 2 attribute arguments, but had " << args.size();
3709e0b5533SMathieu Fehr       return failure();
3719e0b5533SMathieu Fehr     }
3729e0b5533SMathieu Fehr     return success();
3739e0b5533SMathieu Fehr   };
3749e0b5533SMathieu Fehr 
3759e0b5533SMathieu Fehr   auto parser = [](AsmParser &parser,
3769e0b5533SMathieu Fehr                    llvm::SmallVectorImpl<Attribute> &parsedParams) {
3779e0b5533SMathieu Fehr     Attribute leftAttr, rightAttr;
3789e0b5533SMathieu Fehr     if (parser.parseLess() || parser.parseAttribute(leftAttr) ||
3799e0b5533SMathieu Fehr         parser.parseColon() || parser.parseAttribute(rightAttr) ||
3809e0b5533SMathieu Fehr         parser.parseGreater())
3819e0b5533SMathieu Fehr       return failure();
3829e0b5533SMathieu Fehr     parsedParams.push_back(leftAttr);
3839e0b5533SMathieu Fehr     parsedParams.push_back(rightAttr);
3849e0b5533SMathieu Fehr     return success();
3859e0b5533SMathieu Fehr   };
3869e0b5533SMathieu Fehr 
3879e0b5533SMathieu Fehr   auto printer = [](AsmPrinter &printer, ArrayRef<Attribute> params) {
3889e0b5533SMathieu Fehr     printer << "<" << params[0] << ":" << params[1] << ">";
3899e0b5533SMathieu Fehr   };
3909e0b5533SMathieu Fehr 
3919e0b5533SMathieu Fehr   return DynamicAttrDefinition::get("dynamic_custom_assembly_format",
3929e0b5533SMathieu Fehr                                     testDialect, std::move(verifier),
3939e0b5533SMathieu Fehr                                     std::move(parser), std::move(printer));
3949e0b5533SMathieu Fehr }
3959e0b5533SMathieu Fehr 
3969e0b5533SMathieu Fehr //===----------------------------------------------------------------------===//
39783ef862fSRiver Riddle // TestDialect
39883ef862fSRiver Riddle //===----------------------------------------------------------------------===//
39983ef862fSRiver Riddle 
40031bb8efdSRiver Riddle void TestDialect::registerAttributes() {
40131bb8efdSRiver Riddle   addAttributes<
40231bb8efdSRiver Riddle #define GET_ATTRDEF_LIST
40331bb8efdSRiver Riddle #include "TestAttrDefs.cpp.inc"
40431bb8efdSRiver Riddle       >();
4059e0b5533SMathieu Fehr   registerDynamicAttr(getDynamicSingletonAttr(this));
4069e0b5533SMathieu Fehr   registerDynamicAttr(getDynamicPairAttr(this));
4079e0b5533SMathieu Fehr   registerDynamicAttr(getDynamicCustomAssemblyFormatAttr(this));
40831bb8efdSRiver Riddle }
409