[Mlir-commits] [mlir] 6971b83 - [mlir][irdl] Add Variadicity to IRDL operations

Mathieu Fehr llvmlistbot at llvm.org
Wed Jul 26 10:17:21 PDT 2023


Author: Mathieu Fehr
Date: 2023-07-26T18:20:48+01:00
New Revision: 6971b83b2fddf13a42cd080ef86a54397a887f63

URL: https://github.com/llvm/llvm-project/commit/6971b83b2fddf13a42cd080ef86a54397a887f63
DIFF: https://github.com/llvm/llvm-project/commit/6971b83b2fddf13a42cd080ef86a54397a887f63.diff

LOG: [mlir][irdl] Add Variadicity to IRDL operations

This patch adds optional and variadic operands and results
to IRDL. These are added using the `irdl.variadicity` attribute,
which has to be attached to every `irdl.operands` and `irdl.results`
operations.

For instance:
```mlir
irdl.operands(%0, single %1, optional %2, variadic %3)
```
has 4 operand definitions. The first two are single operands,
the second one is optional, and the last one is variadic.

Note that this patch only adds the variadicities to the definition,
but does not consider them when loading a dialect at runtime. This
will be done in the next patch.

Reviewed By: Mogball, unterumarmung

Differential Revision: https://reviews.llvm.org/D153983

Added: 
    mlir/include/mlir/Dialect/IRDL/IR/IRDLAttributes.td
    mlir/test/Dialect/IRDL/variadics-error.irdl.mlir
    mlir/test/Dialect/IRDL/variadics.irdl.mlir

Modified: 
    mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
    mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
    mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
    mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
    mlir/lib/Dialect/IRDL/IR/IRDL.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
index 1a408834bc305c..6cacf97b982baa 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
+++ b/mlir/include/mlir/Dialect/IRDL/IR/CMakeLists.txt
@@ -20,3 +20,12 @@ mlir_tablegen(IRDLTypesGen.h.inc -gen-typedef-decls)
 mlir_tablegen(IRDLTypesGen.cpp.inc -gen-typedef-defs)
 add_public_tablegen_target(MLIRIRDLTypesIncGen)
 add_dependencies(mlir-generic-headers MLIRIRDLTypesIncGen)
+
+# Add IRDL attributes
+set(LLVM_TARGET_DEFINITIONS IRDLAttributes.td)
+mlir_tablegen(IRDLEnums.h.inc -gen-enum-decls)
+mlir_tablegen(IRDLEnums.cpp.inc -gen-enum-defs)
+mlir_tablegen(IRDLAttributes.h.inc -gen-attrdef-decls)
+mlir_tablegen(IRDLAttributes.cpp.inc -gen-attrdef-defs)
+add_public_tablegen_target(MLIRIRDLAttributesIncGen)
+add_dependencies(mlir-generic-headers MLIRIRDLAttributesIncGen)

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
index 0595b345b11ef2..0e72cee3c6e879 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.h
@@ -39,6 +39,11 @@ class OpDefAttr;
 #define GET_TYPEDEF_CLASSES
 #include "mlir/Dialect/IRDL/IR/IRDLTypesGen.h.inc"
 
+#include "mlir/Dialect/IRDL/IR/IRDLEnums.h.inc"
+
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLAttributes.h.inc"
+
 #define GET_OP_CLASSES
 #include "mlir/Dialect/IRDL/IR/IRDLOps.h.inc"
 

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
index ab92821e658f69..9480e2c10aec7c 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDL.td
@@ -69,6 +69,7 @@ def IRDL_Dialect : Dialect {
     attribute. The rationale of this is to simplify the dialect.
   }];
 
+  let useDefaultAttributePrinterParser = 1;
   let useDefaultTypePrinterParser = 1;
   let usePropertiesForAttributes = 1;
 

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLAttributes.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDLAttributes.td
new file mode 100644
index 00000000000000..1bfa7f5cb894b3
--- /dev/null
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLAttributes.td
@@ -0,0 +1,52 @@
+//===- IRDLAttributes.td - IR Definition Language Dialect --*- tablegen -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the attributes used in IRDL.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_DIALECT_IRDL_IR_IRDLATTRIBUTES
+#define MLIR_DIALECT_IRDL_IR_IRDLATTRIBUTES
+
+include "IRDL.td"
+include "mlir/IR/AttrTypeBase.td"
+include "mlir/IR/EnumAttr.td"
+
+def Variadicity : I32EnumAttr<
+    "Variadicity", "variadicity kind",
+    [
+      I32EnumAttrCase<"single",  0>,
+      I32EnumAttrCase<"optional",  1>,
+      I32EnumAttrCase<"variadic", 2>,
+    ]> {
+  let cppNamespace = "::mlir::irdl";
+  let genSpecializedAttr = 0;
+}
+
+def VariadicityAttr : EnumAttr<IRDL_Dialect, Variadicity, "variadicity"> {
+  let summary =
+    "A variadicity kind. Can be either 'single', 'optional', or 'variadic'";
+  let description = [{
+    A `irdl.variadicity` attribute specifies that the associated operand or
+    result definition is either a single definition (the default), an
+    optional definition, or a variadic definition.
+
+    For instance:
+    ```mlir
+    irdl.operands (%arg1, single %arg2, optional %arg3, variadic %arg4)
+    ```
+
+    In this example, both %arg1 and %arg2 are single operands, %arg3 is an
+    optional operand, and %arg4 is a variadic operand.
+  }];
+}
+
+def VariadicityArrayAttr : ArrayOfAttr<IRDL_Dialect, "VariadicityArray", "variadicity_array",
+                            VariadicityAttr.cppClassName> {}
+
+#endif // MLIR_DIALECT_IRDL_IR_IRDLATTRIBUTES

diff  --git a/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
index dfa97c865118fe..e88a80d0793416 100644
--- a/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
+++ b/mlir/include/mlir/Dialect/IRDL/IR/IRDLOps.td
@@ -14,6 +14,7 @@
 #define MLIR_DIALECT_IRDL_IR_IRDLOPS
 
 include "IRDL.td"
+include "IRDLAttributes.td"
 include "IRDLTypes.td"
 include "IRDLInterfaces.td"
 include "mlir/Interfaces/SideEffectInterfaces.td"
@@ -223,10 +224,25 @@ def IRDL_OperandsOp : IRDL_Op<"operands", [HasParent<"OperationOp">]> {
 
     The `mul` operation will expect two operands of type `cmath.complex`, that
     have the same type, and return a result of the same type.
+
+    The operands can also be marked as variadic or optional:
+    ```mlir
+    irdl.operands(%0, single %1, optional %2, variadic %3)
+    ```
+    
+    Here, %0 and %1 are required single operands, %2 is an optional operand,
+    and %3 is a variadic operand.
+
+    When more than one operand is marked as optional or variadic, the operation
+    will expect a 'operand_segment_sizes' attribute that defines the number of
+    operands in each segment.
   }];
 
-  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
-  let assemblyFormat = " `(` $args `)` attr-dict ";
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args, 
+                        VariadicityArrayAttr:$variadicity);
+  let assemblyFormat =
+    "`` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict";
+  let hasVerifier = true;
 }
 
 def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
@@ -254,10 +270,25 @@ def IRDL_ResultsOp : IRDL_Op<"results", [HasParent<"OperationOp">]> {
 
     The operation will expect one operand of the `cmath.complex` type, and two
     results that have the underlying type of the `cmath.complex`.
+
+    The results can also be marked as variadic or optional:
+    ```mlir
+    irdl.results(%0, single %1, optional %2, variadic %3)
+    ```
+    
+    Here, %0 and %1 are required single results, %2 is an optional result,
+    and %3 is a variadic result.
+
+    When more than one result is marked as optional or variadic, the operation
+    will expect a 'result_segment_sizes' attribute that defines the number of
+    results in each segment.
   }];
 
-  let arguments = (ins Variadic<IRDL_AttributeType>:$args);
-  let assemblyFormat = " `(` $args `)` attr-dict ";
+  let arguments = (ins Variadic<IRDL_AttributeType>:$args, 
+                        VariadicityArrayAttr:$variadicity);
+  let assemblyFormat =
+    " `` custom<ValuesWithVariadicity>($args, $variadicity) attr-dict";
+  let hasVerifier = true;
 }
 
 def IRDL_AttributesOp : IRDL_Op<"attributes", [HasParent<"OperationOp">]> {

diff  --git a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
index 841f93c6d079dc..009fc0d144a81e 100644
--- a/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
+++ b/mlir/lib/Dialect/IRDL/IR/IRDL.cpp
@@ -39,6 +39,10 @@ void IRDLDialect::initialize() {
 #define GET_TYPEDEF_LIST
 #include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
       >();
+  addAttributes<
+#define GET_ATTRDEF_LIST
+#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
+      >();
 }
 
 //===----------------------------------------------------------------------===//
@@ -71,9 +75,35 @@ LogicalResult DialectOp::verify() {
   return success();
 }
 
+LogicalResult OperandsOp::verify() {
+  size_t numVariadicities = getVariadicity().size();
+  size_t numOperands = getNumOperands();
+
+  if (numOperands != numVariadicities)
+    return emitOpError()
+           << "the number of operands and their variadicities must be "
+              "the same, but got "
+           << numOperands << " and " << numVariadicities << " respectively";
+
+  return success();
+}
+
+LogicalResult ResultsOp::verify() {
+  size_t numVariadicities = getVariadicity().size();
+  size_t numOperands = this->getNumOperands();
+
+  if (numOperands != numVariadicities)
+    return emitOpError()
+           << "the number of operands and their variadicities must be "
+              "the same, but got "
+           << numOperands << " and " << numVariadicities << " respectively";
+
+  return success();
+}
+
 LogicalResult AttributesOp::verify() {
-  const size_t namesSize = getAttributeValueNames().size();
-  const size_t valuesSize = getAttributeValues().size();
+  size_t namesSize = getAttributeValueNames().size();
+  size_t valuesSize = getAttributeValues().size();
 
   if (namesSize != valuesSize)
     return emitOpError()
@@ -84,6 +114,83 @@ LogicalResult AttributesOp::verify() {
   return success();
 }
 
+/// Parse a value with its variadicity first. By default, the variadicity is
+/// single.
+///
+/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
+static ParseResult
+parseValueWithVariadicity(OpAsmParser &p,
+                          OpAsmParser::UnresolvedOperand &operand,
+                          VariadicityAttr &variadicityAttr) {
+  MLIRContext *ctx = p.getBuilder().getContext();
+
+  // Parse the variadicity, if present
+  if (p.parseOptionalKeyword("single").succeeded()) {
+    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
+  } else if (p.parseOptionalKeyword("optional").succeeded()) {
+    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::optional);
+  } else if (p.parseOptionalKeyword("variadic").succeeded()) {
+    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::variadic);
+  } else {
+    variadicityAttr = VariadicityAttr::get(ctx, Variadicity::single);
+  }
+
+  // Parse the value
+  if (p.parseOperand(operand))
+    return failure();
+  return success();
+}
+
+/// Parse a list of values with their variadicities first. By default, the
+/// variadicity is single.
+///
+/// values-with-variadicity ::=
+///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
+/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
+static ParseResult parseValuesWithVariadicity(
+    OpAsmParser &p, SmallVectorImpl<OpAsmParser::UnresolvedOperand> &operands,
+    VariadicityArrayAttr &variadicityAttr) {
+  Builder &builder = p.getBuilder();
+  MLIRContext *ctx = builder.getContext();
+  SmallVector<VariadicityAttr> variadicities;
+
+  // Parse a single value with its variadicity
+  auto parseOne = [&] {
+    OpAsmParser::UnresolvedOperand operand;
+    VariadicityAttr variadicity;
+    if (parseValueWithVariadicity(p, operand, variadicity))
+      return failure();
+    operands.push_back(operand);
+    variadicities.push_back(variadicity);
+    return success();
+  };
+
+  if (p.parseCommaSeparatedList(OpAsmParser::Delimiter::Paren, parseOne))
+    return failure();
+  variadicityAttr = VariadicityArrayAttr::get(ctx, variadicities);
+  return success();
+}
+
+/// Print a list of values with their variadicities first. By default, the
+/// variadicity is single.
+///
+/// values-with-variadicity ::=
+///   `(` (value-with-variadicity (`,` value-with-variadicity)*)? `)`
+/// value-with-variadicity ::= ("single" | "optional" | "variadic")? ssa-value
+static void printValuesWithVariadicity(OpAsmPrinter &p, Operation *op,
+                                       OperandRange operands,
+                                       VariadicityArrayAttr variadicityAttr) {
+  p << "(";
+  interleaveComma(llvm::seq<int>(0, operands.size()), p, [&](int i) {
+    Variadicity variadicity = variadicityAttr[i].getValue();
+    if (variadicity != Variadicity::single) {
+      p << stringifyVariadicity(variadicity) << " ";
+    }
+    p << operands[i];
+  });
+  p << ")";
+}
+
 static ParseResult
 parseAttributesOp(OpAsmParser &p,
                   SmallVectorImpl<OpAsmParser::UnresolvedOperand> &attrOperands,
@@ -119,5 +226,10 @@ static void printAttributesOp(OpAsmPrinter &p, AttributesOp op,
 #define GET_TYPEDEF_CLASSES
 #include "mlir/Dialect/IRDL/IR/IRDLTypesGen.cpp.inc"
 
+#include "mlir/Dialect/IRDL/IR/IRDLEnums.cpp.inc"
+
+#define GET_ATTRDEF_CLASSES
+#include "mlir/Dialect/IRDL/IR/IRDLAttributes.cpp.inc"
+
 #define GET_OP_CLASSES
 #include "mlir/Dialect/IRDL/IR/IRDLOps.cpp.inc"

diff  --git a/mlir/test/Dialect/IRDL/variadics-error.irdl.mlir b/mlir/test/Dialect/IRDL/variadics-error.irdl.mlir
new file mode 100644
index 00000000000000..67fa94ea8b7427
--- /dev/null
+++ b/mlir/test/Dialect/IRDL/variadics-error.irdl.mlir
@@ -0,0 +1,43 @@
+// RUN: mlir-opt %s -verify-diagnostics -split-input-file
+
+irdl.dialect @errors {
+  irdl.operation @operands {
+    %0 = irdl.is i32
+
+    // expected-error at +1 {{'irdl.operands' op the number of operands and their variadicities must be the same, but got 2 and 1 respectively}}
+    "irdl.operands"(%0, %0) <{variadicity = #irdl<variadicity_array[single]>}> : (!irdl.attribute, !irdl.attribute) -> ()
+  }
+}
+
+// -----
+
+irdl.dialect @errors {
+  irdl.operation @operands2 {
+    %0 = irdl.is i32
+   
+    // expected-error at +1 {{'irdl.operands' op the number of operands and their variadicities must be the same, but got 1 and 2 respectively}}
+    "irdl.operands"(%0) <{variadicity = #irdl<variadicity_array[single, single]>}> : (!irdl.attribute) -> ()
+  }
+}
+
+// -----
+
+irdl.dialect @errors {
+  irdl.operation @results {
+    %0 = irdl.is i32
+
+    // expected-error at +1 {{'irdl.results' op the number of operands and their variadicities must be the same, but got 2 and 1 respectively}}
+    "irdl.results"(%0, %0) <{variadicity = #irdl<variadicity_array[single]>}> : (!irdl.attribute, !irdl.attribute) -> ()
+  }
+}
+
+// -----
+
+irdl.dialect @errors {
+  irdl.operation @results2 {
+    %0 = irdl.is i32
+   
+    // expected-error at +1 {{'irdl.results' op the number of operands and their variadicities must be the same, but got 1 and 2 respectively}}
+    "irdl.results"(%0) <{variadicity = #irdl<variadicity_array[single, single]>}> : (!irdl.attribute) -> ()
+  }
+}

diff  --git a/mlir/test/Dialect/IRDL/variadics.irdl.mlir b/mlir/test/Dialect/IRDL/variadics.irdl.mlir
new file mode 100644
index 00000000000000..6c051d0eaad487
--- /dev/null
+++ b/mlir/test/Dialect/IRDL/variadics.irdl.mlir
@@ -0,0 +1,102 @@
+// RUN: mlir-opt %s | mlir-opt | FileCheck %s
+
+// CHECK: irdl.dialect @testvar {
+irdl.dialect @testvar {
+
+  // CHECK-LABEL: irdl.operation @single_operand {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i32
+  // CHECK-NEXT:    irdl.operands(%[[v0]])
+  // CHECK-NEXT:  }
+  irdl.operation @single_operand {
+    %0 = irdl.is i32
+    irdl.operands(single %0)
+  }
+
+  // CHECK-LABEL: irdl.operation @var_operand {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.operands(%[[v0]], variadic %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @var_operand {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.operands(%0, variadic %1, %2)
+  }
+
+  // CHECK-LABEL: irdl.operation @opt_operand {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.operands(%[[v0]], variadic %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @opt_operand {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.operands(%0, variadic %1, %2)
+  }
+
+  // CHECK-LABEL: irdl.operation @var_and_opt_operand {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.operands(variadic %[[v0]], optional %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @var_and_opt_operand {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.operands(variadic %0, optional %1, %2)
+  }
+
+
+  // CHECK-LABEL: irdl.operation @single_result {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i32
+  // CHECK-NEXT:    irdl.results(%[[v0]])
+  // CHECK-NEXT:  }
+  irdl.operation @single_result {
+    %0 = irdl.is i32
+    irdl.results(single %0)
+  }
+
+  // CHECK-LABEL: irdl.operation @var_result {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.results(%[[v0]], variadic %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @var_result {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.results(%0, variadic %1, %2)
+  }
+
+  // CHECK-LABEL: irdl.operation @opt_result {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.results(%[[v0]], variadic %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @opt_result {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.results(%0, variadic %1, %2)
+  }
+
+  // CHECK-LABEL: irdl.operation @var_and_opt_result {
+  // CHECK-NEXT:    %[[v0:[^ ]*]] = irdl.is i16 
+  // CHECK-NEXT:    %[[v1:[^ ]*]] = irdl.is i32 
+  // CHECK-NEXT:    %[[v2:[^ ]*]] = irdl.is i64 
+  // CHECK-NEXT:    irdl.results(variadic %[[v0]], optional %[[v1]], %[[v2]])
+  // CHECK-NEXT:  }
+  irdl.operation @var_and_opt_result {
+    %0 = irdl.is i16
+    %1 = irdl.is i32
+    %2 = irdl.is i64
+    irdl.results(variadic %0, optional %1, %2)
+  }
+}


        


More information about the Mlir-commits mailing list