575 lines · cpp
1//===- TestAttributes.cpp - MLIR Test Dialect Attributes --------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains attributes defined by the TestDialect for testing various10// features of MLIR.11//12//===----------------------------------------------------------------------===//13 14#include "TestAttributes.h"15#include "TestDialect.h"16#include "TestTypes.h"17#include "mlir/IR/Attributes.h"18#include "mlir/IR/Builders.h"19#include "mlir/IR/DialectImplementation.h"20#include "mlir/IR/ExtensibleDialect.h"21#include "mlir/IR/OpImplementation.h"22#include "mlir/IR/Types.h"23#include "llvm/ADT/APFloat.h"24#include "llvm/ADT/Hashing.h"25#include "llvm/ADT/StringExtras.h"26#include "llvm/ADT/TypeSwitch.h"27#include "llvm/ADT/bit.h"28#include "llvm/Support/ErrorHandling.h"29#include "llvm/Support/raw_ostream.h"30 31using namespace mlir;32using namespace test;33 34//===----------------------------------------------------------------------===//35// CompoundAAttr36//===----------------------------------------------------------------------===//37 38Attribute CompoundAAttr::parse(AsmParser &parser, Type type) {39 int widthOfSomething;40 Type oneType;41 SmallVector<int, 4> arrayOfInts;42 if (parser.parseLess() || parser.parseInteger(widthOfSomething) ||43 parser.parseComma() || parser.parseType(oneType) || parser.parseComma() ||44 parser.parseLSquare())45 return Attribute();46 47 int intVal;48 while (!*parser.parseOptionalInteger(intVal)) {49 arrayOfInts.push_back(intVal);50 if (parser.parseOptionalComma())51 break;52 }53 54 if (parser.parseRSquare() || parser.parseGreater())55 return Attribute();56 return get(parser.getContext(), widthOfSomething, oneType, arrayOfInts);57}58 59void CompoundAAttr::print(AsmPrinter &printer) const {60 printer << "<" << getWidthOfSomething() << ", " << getOneType() << ", [";61 llvm::interleaveComma(getArrayOfInts(), printer);62 printer << "]>";63}64 65//===----------------------------------------------------------------------===//66// CompoundAAttr67//===----------------------------------------------------------------------===//68 69Attribute TestDecimalShapeAttr::parse(AsmParser &parser, Type type) {70 if (parser.parseLess()) {71 return Attribute();72 }73 SmallVector<int64_t> shape;74 if (parser.parseOptionalGreater()) {75 auto parseDecimal = [&]() {76 shape.emplace_back();77 auto parseResult = parser.parseOptionalDecimalInteger(shape.back());78 if (!parseResult.has_value() || failed(*parseResult)) {79 parser.emitError(parser.getCurrentLocation()) << "expected an integer";80 return failure();81 }82 return success();83 };84 if (failed(parseDecimal())) {85 return Attribute();86 }87 while (failed(parser.parseOptionalGreater())) {88 if (failed(parser.parseXInDimensionList()) || failed(parseDecimal())) {89 return Attribute();90 }91 }92 }93 return get(parser.getContext(), shape);94}95 96void TestDecimalShapeAttr::print(AsmPrinter &printer) const {97 printer << "<";98 llvm::interleave(getShape(), printer, "x");99 printer << ">";100}101 102Attribute TestI64ElementsAttr::parse(AsmParser &parser, Type type) {103 SmallVector<uint64_t> elements;104 if (parser.parseLess() || parser.parseLSquare())105 return Attribute();106 uint64_t intVal;107 while (succeeded(*parser.parseOptionalInteger(intVal))) {108 elements.push_back(intVal);109 if (parser.parseOptionalComma())110 break;111 }112 113 if (parser.parseRSquare() || parser.parseGreater())114 return Attribute();115 return parser.getChecked<TestI64ElementsAttr>(116 parser.getContext(), llvm::cast<ShapedType>(type), elements);117}118 119void TestI64ElementsAttr::print(AsmPrinter &printer) const {120 printer << "<[";121 llvm::interleaveComma(getElements(), printer);122 printer << "]>";123}124 125LogicalResult126TestI64ElementsAttr::verify(function_ref<InFlightDiagnostic()> emitError,127 ShapedType type, ArrayRef<uint64_t> elements) {128 if (type.getNumElements() != static_cast<int64_t>(elements.size())) {129 return emitError()130 << "number of elements does not match the provided shape type, got: "131 << elements.size() << ", but expected: " << type.getNumElements();132 }133 if (type.getRank() != 1 || !type.getElementType().isSignlessInteger(64))134 return emitError() << "expected single rank 64-bit shape type, but got: "135 << type;136 return success();137}138 139LogicalResult TestAttrWithFormatAttr::verify(140 function_ref<InFlightDiagnostic()> emitError, int64_t one, std::string two,141 IntegerAttr three, ArrayRef<int> four, uint64_t five, ArrayRef<int> six,142 ArrayRef<AttrWithTypeBuilderAttr> arrayOfAttrs) {143 if (four.size() != static_cast<unsigned>(one))144 return emitError() << "expected 'one' to equal 'four.size()'";145 return success();146}147 148//===----------------------------------------------------------------------===//149// Utility Functions for Generated Attributes150//===----------------------------------------------------------------------===//151 152static FailureOr<SmallVector<int>> parseIntArray(AsmParser &parser) {153 SmallVector<int> ints;154 if (parser.parseLSquare() || parser.parseCommaSeparatedList([&]() {155 ints.push_back(0);156 return parser.parseInteger(ints.back());157 }) ||158 parser.parseRSquare())159 return failure();160 return ints;161}162 163static void printIntArray(AsmPrinter &printer, ArrayRef<int> ints) {164 printer << '[';165 llvm::interleaveComma(ints, printer);166 printer << ']';167}168 169//===----------------------------------------------------------------------===//170// TestSubElementsAccessAttr171//===----------------------------------------------------------------------===//172 173Attribute TestSubElementsAccessAttr::parse(::mlir::AsmParser &parser,174 ::mlir::Type type) {175 Attribute first, second, third;176 if (parser.parseLess() || parser.parseAttribute(first) ||177 parser.parseComma() || parser.parseAttribute(second) ||178 parser.parseComma() || parser.parseAttribute(third) ||179 parser.parseGreater()) {180 return {};181 }182 return get(parser.getContext(), first, second, third);183}184 185void TestSubElementsAccessAttr::print(::mlir::AsmPrinter &printer) const {186 printer << "<" << getFirst() << ", " << getSecond() << ", " << getThird()187 << ">";188}189 190//===----------------------------------------------------------------------===//191// TestExtern1DI64ElementsAttr192//===----------------------------------------------------------------------===//193 194ArrayRef<uint64_t> TestExtern1DI64ElementsAttr::getElements() const {195 if (auto *blob = getHandle().getBlob())196 return blob->getDataAs<uint64_t>();197 return {};198}199 200//===----------------------------------------------------------------------===//201// TestCustomAnchorAttr202//===----------------------------------------------------------------------===//203 204static ParseResult parseTrueFalse(AsmParser &p, std::optional<int> &result) {205 bool b;206 if (p.parseInteger(b))207 return failure();208 result = b;209 return success();210}211 212static void printTrueFalse(AsmPrinter &p, std::optional<int> result) {213 p << (*result ? "true" : "false");214}215 216//===----------------------------------------------------------------------===//217// TestCopyCountAttr Implementation218//===----------------------------------------------------------------------===//219 220LogicalResult TestCopyCountAttr::verify(221 llvm::function_ref<::mlir::InFlightDiagnostic()> /*emitError*/,222 CopyCount /*copy_count*/) {223 return success();224}225 226//===----------------------------------------------------------------------===//227// CopyCountAttr Implementation228//===----------------------------------------------------------------------===//229 230CopyCount::CopyCount(const CopyCount &rhs) : value(rhs.value) {231 CopyCount::counter++;232}233 234CopyCount &CopyCount::operator=(const CopyCount &rhs) {235 CopyCount::counter++;236 value = rhs.value;237 return *this;238}239 240int CopyCount::counter;241 242static bool operator==(const test::CopyCount &lhs, const test::CopyCount &rhs) {243 return lhs.value == rhs.value;244}245 246llvm::raw_ostream &test::operator<<(llvm::raw_ostream &os,247 const test::CopyCount &value) {248 return os << value.value;249}250 251template <>252struct mlir::FieldParser<test::CopyCount> {253 static FailureOr<test::CopyCount> parse(AsmParser &parser) {254 std::string value;255 if (parser.parseKeyword(value))256 return failure();257 return test::CopyCount(value);258 }259};260namespace test {261llvm::hash_code hash_value(const test::CopyCount ©Count) {262 return llvm::hash_value(copyCount.value);263}264} // namespace test265 266//===----------------------------------------------------------------------===//267// TestConditionalAliasAttr268//===----------------------------------------------------------------------===//269 270/// Attempt to parse the conditionally-aliased string attribute as a keyword or271/// string, else try to parse an alias.272static ParseResult parseConditionalAlias(AsmParser &p, StringAttr &value) {273 std::string str;274 if (succeeded(p.parseOptionalKeywordOrString(&str))) {275 value = StringAttr::get(p.getContext(), str);276 return success();277 }278 return p.parseAttribute(value);279}280 281/// Print the string attribute as an alias if it has one, otherwise print it as282/// a keyword if possible.283static void printConditionalAlias(AsmPrinter &p, StringAttr value) {284 if (succeeded(p.printAlias(value)))285 return;286 p.printKeywordOrString(value);287}288 289//===----------------------------------------------------------------------===//290// Custom Float Attribute291//===----------------------------------------------------------------------===//292 293static void printCustomFloatAttr(AsmPrinter &p, StringAttr typeStrAttr,294 APFloat value) {295 p << typeStrAttr << " : " << value;296}297 298static ParseResult parseCustomFloatAttr(AsmParser &p, StringAttr &typeStrAttr,299 FailureOr<APFloat> &value) {300 301 std::string str;302 if (p.parseString(&str))303 return failure();304 305 typeStrAttr = StringAttr::get(p.getContext(), str);306 307 if (p.parseColon())308 return failure();309 310 const llvm::fltSemantics *semantics;311 if (str == "float")312 semantics = &llvm::APFloat::IEEEsingle();313 else if (str == "double")314 semantics = &llvm::APFloat::IEEEdouble();315 else if (str == "fp80")316 semantics = &llvm::APFloat::x87DoubleExtended();317 else318 return p.emitError(p.getCurrentLocation(), "unknown float type, expected "319 "'float', 'double' or 'fp80'");320 321 APFloat parsedValue(0.0);322 if (p.parseFloat(*semantics, parsedValue))323 return failure();324 325 value.emplace(parsedValue);326 return success();327}328 329//===----------------------------------------------------------------------===//330// TestCustomStructAttr331//===----------------------------------------------------------------------===//332 333static void printCustomStructAttr(AsmPrinter &p, int64_t value) {334 if (ShapedType::isDynamic(value)) {335 p << "?";336 } else {337 p.printStrippedAttrOrType(value);338 }339}340 341static ParseResult parseCustomStructAttr(AsmParser &p, int64_t &value) {342 if (succeeded(p.parseOptionalQuestion())) {343 value = ShapedType::kDynamic;344 return success();345 }346 return p.parseInteger(value);347}348 349static void printCustomOptStructFieldAttr(AsmPrinter &p, ArrayAttr attr) {350 if (attr && attr.size() == 1 && isa<IntegerAttr>(attr[0])) {351 p << cast<IntegerAttr>(attr[0]).getInt();352 } else {353 p.printStrippedAttrOrType(attr);354 }355}356 357static ParseResult parseCustomOptStructFieldAttr(AsmParser &p,358 ArrayAttr &attr) {359 int64_t value;360 OptionalParseResult result = p.parseOptionalInteger(value);361 if (result.has_value()) {362 if (failed(result.value()))363 return failure();364 attr = ArrayAttr::get(365 p.getContext(),366 {IntegerAttr::get(IntegerType::get(p.getContext(), 64), value)});367 return success();368 }369 return p.parseAttribute(attr);370}371 372//===----------------------------------------------------------------------===//373// TestOpAsmAttrInterfaceAttr374//===----------------------------------------------------------------------===//375 376::mlir::OpAsmDialectInterface::AliasResult377TestOpAsmAttrInterfaceAttr::getAlias(::llvm::raw_ostream &os) const {378 os << "op_asm_attr_interface_";379 os << getValue().getValue();380 return ::mlir::OpAsmDialectInterface::AliasResult::FinalAlias;381}382 383//===----------------------------------------------------------------------===//384// TestConstMemorySpaceAttr385//===----------------------------------------------------------------------===//386 387bool TestConstMemorySpaceAttr::isValidLoad(388 Type type, mlir::ptr::AtomicOrdering ordering,389 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,390 function_ref<InFlightDiagnostic()> emitError) const {391 return true;392}393 394bool TestConstMemorySpaceAttr::isValidStore(395 Type type, mlir::ptr::AtomicOrdering ordering,396 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,397 function_ref<InFlightDiagnostic()> emitError) const {398 if (emitError)399 emitError() << "memory space is read-only";400 return false;401}402 403bool TestConstMemorySpaceAttr::isValidAtomicOp(404 mlir::ptr::AtomicBinOp binOp, Type type, mlir::ptr::AtomicOrdering ordering,405 std::optional<int64_t> alignment, const ::mlir::DataLayout *dataLayout,406 function_ref<InFlightDiagnostic()> emitError) const {407 if (emitError)408 emitError() << "memory space is read-only";409 return false;410}411 412bool TestConstMemorySpaceAttr::isValidAtomicXchg(413 Type type, mlir::ptr::AtomicOrdering successOrdering,414 mlir::ptr::AtomicOrdering failureOrdering, std::optional<int64_t> alignment,415 const ::mlir::DataLayout *dataLayout,416 function_ref<InFlightDiagnostic()> emitError) const {417 if (emitError)418 emitError() << "memory space is read-only";419 return false;420}421 422bool TestConstMemorySpaceAttr::isValidAddrSpaceCast(423 Type tgt, Type src, function_ref<InFlightDiagnostic()> emitError) const {424 if (emitError)425 emitError() << "memory space doesn't allow addrspace casts";426 return false;427}428 429bool TestConstMemorySpaceAttr::isValidPtrIntCast(430 Type intLikeTy, Type ptrLikeTy,431 function_ref<InFlightDiagnostic()> emitError) const {432 if (emitError)433 emitError() << "memory space doesn't allow int-ptr casts";434 return false;435}436 437//===----------------------------------------------------------------------===//438// Tablegen Generated Definitions439//===----------------------------------------------------------------------===//440 441#include "TestAttrInterfaces.cpp.inc"442#include "TestOpEnums.cpp.inc"443#define GET_ATTRDEF_CLASSES444#include "TestAttrDefs.cpp.inc"445 446//===----------------------------------------------------------------------===//447// Dynamic Attributes448//===----------------------------------------------------------------------===//449 450/// Define a singleton dynamic attribute.451static std::unique_ptr<DynamicAttrDefinition>452getDynamicSingletonAttr(TestDialect *testDialect) {453 return DynamicAttrDefinition::get(454 "dynamic_singleton", testDialect,455 [](function_ref<InFlightDiagnostic()> emitError,456 ArrayRef<Attribute> args) {457 if (!args.empty()) {458 emitError() << "expected 0 attribute arguments, but had "459 << args.size();460 return failure();461 }462 return success();463 });464}465 466/// Define a dynamic attribute representing a pair or attributes.467static std::unique_ptr<DynamicAttrDefinition>468getDynamicPairAttr(TestDialect *testDialect) {469 return DynamicAttrDefinition::get(470 "dynamic_pair", testDialect,471 [](function_ref<InFlightDiagnostic()> emitError,472 ArrayRef<Attribute> args) {473 if (args.size() != 2) {474 emitError() << "expected 2 attribute arguments, but had "475 << args.size();476 return failure();477 }478 return success();479 });480}481 482static std::unique_ptr<DynamicAttrDefinition>483getDynamicCustomAssemblyFormatAttr(TestDialect *testDialect) {484 auto verifier = [](function_ref<InFlightDiagnostic()> emitError,485 ArrayRef<Attribute> args) {486 if (args.size() != 2) {487 emitError() << "expected 2 attribute arguments, but had " << args.size();488 return failure();489 }490 return success();491 };492 493 auto parser = [](AsmParser &parser,494 llvm::SmallVectorImpl<Attribute> &parsedParams) {495 Attribute leftAttr, rightAttr;496 if (parser.parseLess() || parser.parseAttribute(leftAttr) ||497 parser.parseColon() || parser.parseAttribute(rightAttr) ||498 parser.parseGreater())499 return failure();500 parsedParams.push_back(leftAttr);501 parsedParams.push_back(rightAttr);502 return success();503 };504 505 auto printer = [](AsmPrinter &printer, ArrayRef<Attribute> params) {506 printer << "<" << params[0] << ":" << params[1] << ">";507 };508 509 return DynamicAttrDefinition::get("dynamic_custom_assembly_format",510 testDialect, std::move(verifier),511 std::move(parser), std::move(printer));512}513 514//===----------------------------------------------------------------------===//515// SlashAttr516//===----------------------------------------------------------------------===//517 518Attribute SlashAttr::parse(AsmParser &parser, Type type) {519 int lhs, rhs;520 521 if (parser.parseLess() || parser.parseInteger(lhs) || parser.parseSlash() ||522 parser.parseInteger(rhs) || parser.parseGreater())523 return Attribute();524 525 return SlashAttr::get(parser.getContext(), lhs, rhs);526}527 528void SlashAttr::print(AsmPrinter &printer) const {529 printer << "<" << getLhs() << " / " << getRhs() << ">";530}531 532//===----------------------------------------------------------------------===//533// TestCustomStorageCtorAttr534//===----------------------------------------------------------------------===//535 536test::detail::TestCustomStorageCtorAttrAttrStorage *537test::detail::TestCustomStorageCtorAttrAttrStorage::construct(538 mlir::StorageUniquer::StorageAllocator &, std::tuple<int> &&) {539 // Note: this tests linker error ("undefined symbol"), the actual540 // implementation is not important.541 return nullptr;542}543 544//===----------------------------------------------------------------------===//545// TestTensorEncodingAttr546//===----------------------------------------------------------------------===//547 548::llvm::LogicalResult TestTensorEncodingAttr::verifyEncoding(549 mlir::ArrayRef<int64_t> shape, mlir::Type elementType,550 llvm::function_ref<::mlir::InFlightDiagnostic()> emitError) const {551 return mlir::success();552}553 554//===----------------------------------------------------------------------===//555// TestMemRefLayoutAttr556//===----------------------------------------------------------------------===//557 558mlir::AffineMap TestMemRefLayoutAttr::getAffineMap() const {559 return mlir::AffineMap::getMultiDimIdentityMap(1, getContext());560}561 562//===----------------------------------------------------------------------===//563// TestDialect564//===----------------------------------------------------------------------===//565 566void TestDialect::registerAttributes() {567 addAttributes<568#define GET_ATTRDEF_LIST569#include "TestAttrDefs.cpp.inc"570 >();571 registerDynamicAttr(getDynamicSingletonAttr(this));572 registerDynamicAttr(getDynamicPairAttr(this));573 registerDynamicAttr(getDynamicCustomAssemblyFormatAttr(this));574}575