brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.0 KiB · 197a590 Raw
477 lines · cpp
1//===- IRDL.cpp - IRDL dialect ----------------------------------*- C++ -*-===//2//3// This file is licensed 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#include "mlir/Dialect/IRDL/IR/IRDL.h"10#include "mlir/Dialect/IRDL/IRDLSymbols.h"11#include "mlir/IR/Builders.h"12#include "mlir/IR/BuiltinAttributes.h"13#include "mlir/IR/Diagnostics.h"14#include "mlir/IR/DialectImplementation.h"15#include "mlir/IR/ExtensibleDialect.h"16#include "mlir/IR/OpDefinition.h"17#include "mlir/IR/OpImplementation.h"18#include "mlir/IR/Operation.h"19#include "mlir/Support/LLVM.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/SetOperations.h"22#include "llvm/ADT/StringExtras.h"23#include "llvm/ADT/TypeSwitch.h"24#include "llvm/Support/Casting.h"25 26using namespace mlir;27using namespace mlir::irdl;28 29//===----------------------------------------------------------------------===//30// IRDL dialect.31//===----------------------------------------------------------------------===//32 33#include "mlir/Dialect/IRDL/IR/IRDL.cpp.inc"34 35#include "mlir/Dialect/IRDL/IR/IRDLDialect.cpp.inc"36 37void IRDLDialect::initialize() {38  addOperations<39#define GET_OP_LIST40#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"41      >();42  addTypes<43#define GET_TYPEDEF_LIST44#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"45      >();46  addAttributes<47#define GET_ATTRDEF_LIST48#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"49      >();50}51 52//===----------------------------------------------------------------------===//53// Parsing/Printing/Verifying54//===----------------------------------------------------------------------===//55 56/// Parse a region, and add a single block if the region is empty.57/// If no region is parsed, create a new region with a single empty block.58static ParseResult parseSingleBlockRegion(OpAsmParser &p, Region &region) {59  auto regionParseRes = p.parseOptionalRegion(region);60  if (regionParseRes.has_value() && failed(regionParseRes.value()))61    return failure();62 63  // If the region is empty, add a single empty block.64  if (region.empty())65    region.push_back(new Block());66 67  return success();68}69 70static void printSingleBlockRegion(OpAsmPrinter &p, Operation *op,71                                   Region &region) {72  if (!region.getBlocks().front().empty())73    p.printRegion(region);74}75static llvm::LogicalResult isValidName(llvm::StringRef in, mlir::Operation *loc,76                                       const Twine &label) {77  if (in.empty())78    return loc->emitError("name of ") << label << " is empty";79 80  bool allowUnderscore = false;81  for (auto &elem : in) {82    if (elem == '_') {83      if (!allowUnderscore)84        return loc->emitError("name of ")85               << label << " should not contain leading or double underscores";86    } else {87      if (!isalnum(elem))88        return loc->emitError("name of ")89               << label90               << " must contain only lowercase letters, digits and "91                  "underscores";92 93      if (llvm::isUpper(elem))94        return loc->emitError("name of ")95               << label << " should not contain uppercase letters";96    }97 98    allowUnderscore = elem != '_';99  }100 101  return success();102}103 104LogicalResult DialectOp::verify() {105  if (!Dialect::isValidNamespace(getName()))106    return emitOpError("invalid dialect name");107  if (failed(isValidName(getSymName(), getOperation(), "dialect")))108    return failure();109 110  return success();111}112 113LogicalResult OperationOp::verify() {114  return isValidName(getSymName(), getOperation(), "operation");115}116 117LogicalResult TypeOp::verify() {118  auto symName = getSymName();119  if (symName.front() == '!')120    symName = symName.substr(1);121  return isValidName(symName, getOperation(), "type");122}123 124LogicalResult AttributeOp::verify() {125  auto symName = getSymName();126  if (symName.front() == '#')127    symName = symName.substr(1);128  return isValidName(symName, getOperation(), "attribute");129}130 131LogicalResult OperationOp::verifyRegions() {132  // Stores pairs of value kinds and the list of names of values of this kind in133  // the operation.134  SmallVector<std::tuple<StringRef, llvm::SmallDenseSet<StringRef>>> valueNames;135 136  auto insertNames = [&](StringRef kind, ArrayAttr names) {137    llvm::SmallDenseSet<StringRef> nameSet;138    nameSet.reserve(names.size());139    for (auto name : names)140      nameSet.insert(llvm::cast<StringAttr>(name).getValue());141    valueNames.emplace_back(kind, std::move(nameSet));142  };143 144  for (Operation &op : getBody().getOps()) {145    TypeSwitch<Operation *>(&op)146        .Case<OperandsOp>(147            [&](OperandsOp op) { insertNames("operands", op.getNames()); })148        .Case<ResultsOp>(149            [&](ResultsOp op) { insertNames("results", op.getNames()); })150        .Case<RegionsOp>(151            [&](RegionsOp op) { insertNames("regions", op.getNames()); });152  }153 154  // Verify that no two operand, result or region share the same name.155  // The absence of duplicates within each value kind is checked by the156  // associated operation's verifier.157  for (size_t i : llvm::seq(valueNames.size())) {158    for (size_t j : llvm::seq(i + 1, valueNames.size())) {159      auto [lhs, lhsSet] = valueNames[i];160      auto &[rhs, rhsSet] = valueNames[j];161      llvm::set_intersect(lhsSet, rhsSet);162      if (!lhsSet.empty())163        return emitOpError("contains a value named '")164               << *lhsSet.begin() << "' for both its " << lhs << " and " << rhs;165    }166  }167 168  return success();169}170 171static LogicalResult verifyNames(Operation *op, StringRef kindName,172                                 ArrayAttr names, size_t numOperands) {173  if (numOperands != names.size())174    return op->emitOpError()175           << "the number of " << kindName176           << "s and their names must be "177              "the same, but got "178           << numOperands << " and " << names.size() << " respectively";179 180  DenseMap<StringRef, size_t> nameMap;181  for (auto [i, name] : llvm::enumerate(names)) {182    StringRef nameRef = llvm::cast<StringAttr>(name).getValue();183 184    if (failed(isValidName(nameRef, op, Twine(kindName) + " #" + Twine(i))))185      return failure();186 187    if (nameMap.contains(nameRef))188      return op->emitOpError() << "name of " << kindName << " #" << i189                               << " is a duplicate of the name of " << kindName190                               << " #" << nameMap[nameRef];191    nameMap.insert({nameRef, i});192  }193 194  return success();195}196 197LogicalResult ParametersOp::verify() {198  return verifyNames(*this, "parameter", getNames(), getNumOperands());199}200 201template <typename ValueListOp>202static LogicalResult verifyOperandsResultsCommon(ValueListOp op,203                                                 StringRef kindName) {204  size_t numVariadicities = op.getVariadicity().size();205  size_t numOperands = op.getNumOperands();206 207  if (numOperands != numVariadicities)208    return op.emitOpError()209           << "the number of " << kindName210           << "s and their variadicities must be "211              "the same, but got "212           << numOperands << " and " << numVariadicities << " respectively";213 214  return verifyNames(op, kindName, op.getNames(), numOperands);215}216 217LogicalResult OperandsOp::verify() {218  return verifyOperandsResultsCommon(*this, "operand");219}220 221LogicalResult ResultsOp::verify() {222  return verifyOperandsResultsCommon(*this, "result");223}224 225LogicalResult AttributesOp::verify() {226  size_t namesSize = getAttributeValueNames().size();227  size_t valuesSize = getAttributeValues().size();228 229  if (namesSize != valuesSize)230    return emitOpError()231           << "the number of attribute names and their constraints must be "232              "the same but got "233           << namesSize << " and " << valuesSize << " respectively";234 235  return success();236}237 238LogicalResult BaseOp::verify() {239  std::optional<StringRef> baseName = getBaseName();240  std::optional<SymbolRefAttr> baseRef = getBaseRef();241  if (baseName.has_value() == baseRef.has_value())242    return emitOpError() << "the base type or attribute should be specified by "243                            "either a name or a reference";244 245  if (baseName &&246      (baseName->empty() || ((*baseName)[0] != '!' && (*baseName)[0] != '#')))247    return emitOpError() << "the base type or attribute name should start with "248                            "'!' or '#'";249 250  return success();251}252 253/// Finds whether the provided symbol is an IRDL type or attribute definition.254/// The source operation must be within a DialectOp.255static LogicalResult256checkSymbolIsTypeOrAttribute(SymbolTableCollection &symbolTable,257                             Operation *source, SymbolRefAttr symbol) {258  Operation *targetOp =259      irdl::lookupSymbolNearDialect(symbolTable, source, symbol);260 261  if (!targetOp)262    return source->emitOpError() << "symbol '" << symbol << "' not found";263 264  if (!isa<TypeOp, AttributeOp>(targetOp))265    return source->emitOpError() << "symbol '" << symbol266                                 << "' does not refer to a type or attribute "267                                    "definition (refers to '"268                                 << targetOp->getName() << "')";269 270  return success();271}272 273LogicalResult BaseOp::verifySymbolUses(SymbolTableCollection &symbolTable) {274  std::optional<SymbolRefAttr> baseRef = getBaseRef();275  if (!baseRef)276    return success();277 278  return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);279}280 281LogicalResult282ParametricOp::verifySymbolUses(SymbolTableCollection &symbolTable) {283  std::optional<SymbolRefAttr> baseRef = getBaseType();284  if (!baseRef)285    return success();286 287  return checkSymbolIsTypeOrAttribute(symbolTable, *this, *baseRef);288}289 290/// Parse a value with its variadicity first. By default, the variadicity is291/// single.292///293/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value294static ParseResult295parseValueWithVariadicity(OpAsmParser &p,296                          OpAsmParser::UnresolvedOperand &operand,297                          VariadicityAttr &variadicityAttr) {298  MLIRContext *ctx = p.getBuilder().getContext();299 300  // Parse the variadicity, if present301  if (p.parseOptionalKeyword("single").succeeded()) {302    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);303  } else if (p.parseOptionalKeyword("optional").succeeded()) {304    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::optional);305  } else if (p.parseOptionalKeyword("variadic").succeeded()) {306    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::variadic);307  } else {308    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);309  }310 311  // Parse the value312  if (p.parseOperand(operand))313    return failure();314  return success();315}316 317static ParseResult parseNamedValueListImpl(318    OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,319    ArrayAttr &valueNamesAttr, VariadicityArrayAttr *variadicityAttr) {320  Builder &builder = p.getBuilder();321  MLIRContext *ctx = builder.getContext();322  SmallVector<Attribute> valueNames;323  SmallVector<VariadicityAttr> variadicities;324 325  // Parse a single value with its variadicity326  auto parseOne = [&] {327    StringRef name;328    OpAsmParser::UnresolvedOperand operand;329    VariadicityAttr variadicity;330    if (p.parseKeyword(&name) || p.parseColon())331      return failure();332 333    if (variadicityAttr) {334      if (parseValueWithVariadicity(p, operand, variadicity))335        return failure();336      variadicities.push_back(variadicity);337    } else {338      if (p.parseOperand(operand))339        return failure();340    }341 342    valueNames.push_back(StringAttr::get(ctx, name));343    operands.push_back(operand);344    return success();345  };346 347  if (p.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOne))348    return failure();349  valueNamesAttr = ArrayAttr::get(ctx, valueNames);350  if (variadicityAttr)351    *variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);352  return success();353}354 355/// Parse a list of named values.356///357/// values ::=358///   `(` (named-value (`,` named-value)*)? `)`359/// named-value := bare-id `:` ssa-value360static ParseResult361parseNamedValueList(OpAsmParser &p,362                    SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,363                    ArrayAttr &valueNamesAttr) {364  return parseNamedValueListImpl(p, operands, valueNamesAttr, nullptr);365}366 367/// Parse a list of named values with their variadicities first. By default, the368/// variadicity is single.369///370/// values-with-variadicity ::=371///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`372/// value-with-variadicity373///   ::= bare-id `:` ("single" | "optional" | "variadic")? ssa-value374static ParseResult parseNamedValueListWithVariadicity(375    OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,376    ArrayAttr &valueNamesAttr, VariadicityArrayAttr &variadicityAttr) {377  return parseNamedValueListImpl(p, operands, valueNamesAttr, &variadicityAttr);378}379 380static void printNamedValueListImpl(OpAsmPrinter &p, Operation *op,381                                    OperandRange operands,382                                    ArrayAttr valueNamesAttr,383                                    VariadicityArrayAttr variadicityAttr) {384  p << "(";385  interleaveComma(llvm::seq<int>(0, operands.size()), p, [&](int i) {386    p << llvm::cast<StringAttr>(valueNamesAttr[i]).getValue() << ": ";387    if (variadicityAttr) {388      Variadicity variadicity = variadicityAttr[i].getValue();389      if (variadicity != Variadicity::single) {390        p << stringifyVariadicity(variadicity) << " ";391      }392    }393    p << operands[i];394  });395  p << ")";396}397 398/// Print a list of named values.399///400/// values ::=401///   `(` (named-value (`,` named-value)*)? `)`402/// named-value := bare-id `:` ssa-value403static void printNamedValueList(OpAsmPrinter &p, Operation *op,404                                OperandRange operands,405                                ArrayAttr valueNamesAttr) {406  printNamedValueListImpl(p, op, operands, valueNamesAttr, nullptr);407}408 409/// Print a list of named values with their variadicities first. By default, the410/// variadicity is single.411///412/// values-with-variadicity ::=413///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`414/// value-with-variadicity ::=415///   bare-id `:` ("single" | "optional" | "variadic")? ssa-value416static void printNamedValueListWithVariadicity(417    OpAsmPrinter &p, Operation *op, OperandRange operands,418    ArrayAttr valueNamesAttr, VariadicityArrayAttr variadicityAttr) {419  printNamedValueListImpl(p, op, operands, valueNamesAttr, variadicityAttr);420}421 422static ParseResult423parseAttributesOp(OpAsmParser &p,424                  SmallVectorImpl<OpAsmParser::UnresolvedOperand> &attrOperands,425                  ArrayAttr &attrNamesAttr) {426  Builder &builder = p.getBuilder();427  SmallVector<Attribute> attrNames;428  if (succeeded(p.parseOptionalLBrace())) {429    auto parseOperands = [&]() {430      if (p.parseAttribute(attrNames.emplace_back()) || p.parseEqual() ||431          p.parseOperand(attrOperands.emplace_back()))432        return failure();433      return success();434    };435    if (p.parseCommaSeparatedList(parseOperands) || p.parseRBrace())436      return failure();437  }438  attrNamesAttr = builder.getArrayAttr(attrNames);439  return success();440}441 442static void printAttributesOp(OpAsmPrinter &p, AttributesOp op,443                              OperandRange attrArgs, ArrayAttr attrNames) {444  if (attrNames.empty())445    return;446  p << "{";447  interleaveComma(llvm::seq<int>(0, attrNames.size()), p,448                  [&](int i) { p << attrNames[i] << " = " << attrArgs[i]; });449  p << '}';450}451 452LogicalResult RegionOp::verify() {453  if (IntegerAttr numberOfBlocks = getNumberOfBlocksAttr())454    if (int64_t number = numberOfBlocks.getInt(); number <= 0) {455      return emitOpError("the number of blocks is expected to be >= 1 but got ")456             << number;457    }458  return success();459}460 461LogicalResult RegionsOp::verify() {462  return verifyNames(*this, "region", getNames(), getNumOperands());463}464 465#include "mlir/Dialect/IRDL/IR/IRDLInterfaces.cpp.inc"466 467#define GET_TYPEDEF_CLASSES468#include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"469 470#include "mlir/Dialect/IRDL/IR/IRDLEnums.cpp.inc"471 472#define GET_ATTRDEF_CLASSES473#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"474 475#define GET_OP_CLASSES476#include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"477