brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.8 KiB · 9c12895 Raw
256 lines · cpp
1//===- IRDLVerifiers.cpp - IRDL verifiers ------------------------- 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// Verifiers for objects declared by IRDL.10//11//===----------------------------------------------------------------------===//12 13#include "mlir/Dialect/IRDL/IRDLVerifiers.h"14#include "mlir/IR/Attributes.h"15#include "mlir/IR/BuiltinAttributes.h"16#include "mlir/IR/Diagnostics.h"17#include "mlir/IR/ExtensibleDialect.h"18#include "mlir/IR/Location.h"19#include "mlir/IR/Region.h"20#include "mlir/IR/Value.h"21 22using namespace mlir;23using namespace mlir::irdl;24 25ConstraintVerifier::ConstraintVerifier(26    ArrayRef<std::unique_ptr<Constraint>> constraints)27    : constraints(constraints), assigned() {28  assigned.resize(this->constraints.size());29}30 31LogicalResult32ConstraintVerifier::verify(function_ref<InFlightDiagnostic()> emitError,33                           Attribute attr, unsigned variable) {34 35  assert(variable < constraints.size() && "invalid constraint variable");36 37  // If the variable is already assigned, check that the attribute is the same.38  if (assigned[variable].has_value()) {39    if (attr == assigned[variable].value()) {40      return success();41    }42    if (emitError)43      return emitError() << "expected '" << assigned[variable].value()44                         << "' but got '" << attr << "'";45    return failure();46  }47 48  // Otherwise, check the constraint and assign the attribute to the variable.49  LogicalResult result = constraints[variable]->verify(emitError, attr, *this);50  if (succeeded(result))51    assigned[variable] = attr;52 53  return result;54}55 56LogicalResult IsConstraint::verify(function_ref<InFlightDiagnostic()> emitError,57                                   Attribute attr,58                                   ConstraintVerifier &context) const {59  if (attr == expectedAttribute)60    return success();61 62  if (emitError)63    return emitError() << "expected '" << expectedAttribute << "' but got '"64                       << attr << "'";65  return failure();66}67 68LogicalResult69BaseAttrConstraint::verify(function_ref<InFlightDiagnostic()> emitError,70                           Attribute attr, ConstraintVerifier &context) const {71  if (attr.getTypeID() == baseTypeID)72    return success();73 74  if (emitError)75    return emitError() << "expected base attribute '" << baseName76                       << "' but got '" << attr.getAbstractAttribute().getName()77                       << "'";78  return failure();79}80 81LogicalResult82BaseTypeConstraint::verify(function_ref<InFlightDiagnostic()> emitError,83                           Attribute attr, ConstraintVerifier &context) const {84  auto typeAttr = dyn_cast<TypeAttr>(attr);85  if (!typeAttr) {86    if (emitError)87      return emitError() << "expected type, got attribute '" << attr;88    return failure();89  }90 91  Type type = typeAttr.getValue();92  if (type.getTypeID() == baseTypeID)93    return success();94 95  if (emitError)96    return emitError() << "expected base type '" << baseName << "' but got '"97                       << type.getAbstractType().getName() << "'";98  return failure();99}100 101LogicalResult DynParametricAttrConstraint::verify(102    function_ref<InFlightDiagnostic()> emitError, Attribute attr,103    ConstraintVerifier &context) const {104 105  // Check that the base is the expected one.106  auto dynAttr = dyn_cast<DynamicAttr>(attr);107  if (!dynAttr || dynAttr.getAttrDef() != attrDef) {108    if (emitError) {109      StringRef dialectName = attrDef->getDialect()->getNamespace();110      StringRef attrName = attrDef->getName();111      return emitError() << "expected base attribute '" << attrName << '.'112                         << dialectName << "' but got '" << attr << "'";113    }114    return failure();115  }116 117  // Check that the parameters satisfy the constraints.118  ArrayRef<Attribute> params = dynAttr.getParams();119  if (params.size() != constraints.size()) {120    if (emitError) {121      StringRef dialectName = attrDef->getDialect()->getNamespace();122      StringRef attrName = attrDef->getName();123      emitError() << "attribute '" << dialectName << "." << attrName124                  << "' expects " << params.size() << " parameters but got "125                  << constraints.size();126    }127    return failure();128  }129 130  for (size_t i = 0, s = params.size(); i < s; i++)131    if (failed(context.verify(emitError, params[i], constraints[i])))132      return failure();133 134  return success();135}136 137LogicalResult DynParametricTypeConstraint::verify(138    function_ref<InFlightDiagnostic()> emitError, Attribute attr,139    ConstraintVerifier &context) const {140  // Check that the base is a TypeAttr.141  auto typeAttr = dyn_cast<TypeAttr>(attr);142  if (!typeAttr) {143    if (emitError)144      return emitError() << "expected type, got attribute '" << attr;145    return failure();146  }147 148  // Check that the type base is the expected one.149  auto dynType = dyn_cast<DynamicType>(typeAttr.getValue());150  if (!dynType || dynType.getTypeDef() != typeDef) {151    if (emitError) {152      StringRef dialectName = typeDef->getDialect()->getNamespace();153      StringRef attrName = typeDef->getName();154      return emitError() << "expected base type '" << dialectName << '.'155                         << attrName << "' but got '" << attr << "'";156    }157    return failure();158  }159 160  // Check that the parameters satisfy the constraints.161  ArrayRef<Attribute> params = dynType.getParams();162  if (params.size() != constraints.size()) {163    if (emitError) {164      StringRef dialectName = typeDef->getDialect()->getNamespace();165      StringRef attrName = typeDef->getName();166      emitError() << "attribute '" << dialectName << "." << attrName167                  << "' expects " << params.size() << " parameters but got "168                  << constraints.size();169    }170    return failure();171  }172 173  for (size_t i = 0, s = params.size(); i < s; i++)174    if (failed(context.verify(emitError, params[i], constraints[i])))175      return failure();176 177  return success();178}179 180LogicalResult181AnyOfConstraint::verify(function_ref<InFlightDiagnostic()> emitError,182                        Attribute attr, ConstraintVerifier &context) const {183  for (unsigned constr : constraints) {184    // We do not pass the `emitError` here, since we want to emit an error185    // only if none of the constraints are satisfied.186    if (succeeded(context.verify({}, attr, constr))) {187      return success();188    }189  }190 191  if (emitError)192    return emitError() << "'" << attr << "' does not satisfy the constraint";193  return failure();194}195 196LogicalResult197AllOfConstraint::verify(function_ref<InFlightDiagnostic()> emitError,198                        Attribute attr, ConstraintVerifier &context) const {199  for (unsigned constr : constraints) {200    if (failed(context.verify(emitError, attr, constr))) {201      return failure();202    }203  }204 205  return success();206}207 208LogicalResult209AnyAttributeConstraint::verify(function_ref<InFlightDiagnostic()> emitError,210                               Attribute attr,211                               ConstraintVerifier &context) const {212  return success();213}214 215LogicalResult RegionConstraint::verify(mlir::Region &region,216                                       ConstraintVerifier &constraintContext) {217  const auto emitError = [parentOp = region.getParentOp()](mlir::Location loc) {218    return [loc, parentOp] {219      InFlightDiagnostic diag = mlir::emitError(loc);220      // If we already have been given location of the parent operation, which221      // might happen when the region location is passed, we do not want to222      // produce the note on the same location223      if (loc != parentOp->getLoc())224        diag.attachNote(parentOp->getLoc()).append("see the operation");225      return diag;226    };227  };228 229  if (blockCount.has_value() && *blockCount != region.getBlocks().size()) {230    return emitError(region.getLoc())()231           << "expected region " << region.getRegionNumber() << " to have "232           << *blockCount << " block(s) but got " << region.getBlocks().size();233  }234 235  if (argumentConstraints.has_value()) {236    auto actualArgs = region.getArguments();237    if (actualArgs.size() != argumentConstraints->size()) {238      const mlir::Location firstArgLoc =239          actualArgs.empty() ? region.getLoc() : actualArgs.front().getLoc();240      return emitError(firstArgLoc)()241             << "expected region " << region.getRegionNumber() << " to have "242             << argumentConstraints->size() << " arguments but got "243             << actualArgs.size();244    }245 246    for (auto [arg, constraint] : llvm::zip(actualArgs, *argumentConstraints)) {247      mlir::Attribute type = TypeAttr::get(arg.getType());248      if (failed(constraintContext.verify(emitError(arg.getLoc()), type,249                                          constraint))) {250        return failure();251      }252    }253  }254  return success();255}256