[Mlir-commits] [mlir] 851a897 - [mlir][llvm] Purge struct_attr

Christian Ulmann llvmlistbot at llvm.org
Thu Feb 9 00:42:32 PST 2023


Author: Christian Ulmann
Date: 2023-02-09T09:41:43+01:00
New Revision: 851a89715cadf411bd66a7cbb9d7567580f08f4c

URL: https://github.com/llvm/llvm-project/commit/851a89715cadf411bd66a7cbb9d7567580f08f4c
DIFF: https://github.com/llvm/llvm-project/commit/851a89715cadf411bd66a7cbb9d7567580f08f4c.diff

LOG: [mlir][llvm] Purge struct_attr

This commit removes the `llvm.struct_attr` which was used to bundle
result attributes that were previously attached to multiple results.
This extension isn't part of LLVM as result attribute semantics cannot
be supported on a struct field granularity.
Furthermore, many usages promoted result attributes to argument
attributes but this does not necessary preserve the semantics.

Reviewed By: gysit

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

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
    mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-callers.mlir
    mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir
    mlir/test/Dialect/LLVMIR/invalid.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
index f0b735cf9e48f..4fd758639ba15 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOpBase.td
@@ -39,7 +39,6 @@ def LLVM_Dialect : Dialect {
     static StringRef getAliasScopesAttrName() { return "alias_scopes"; }
     static StringRef getLoopAttrName() { return "llvm.loop"; }
     static StringRef getAccessGroupsAttrName() { return "access_groups"; }
-    static StringRef getStructAttrsAttrName() { return "llvm.struct_attrs"; }
     static StringRef getTBAAAttrName() { return "llvm.tbaa"; }
 
     /// Names of llvm parameter attributes.
@@ -72,10 +71,6 @@ def LLVM_Dialect : Dialect {
     /// effect when lowering to the LLVMDialect.
     static StringRef getReadnoneAttrName() { return "llvm.readnone"; }
 
-    /// Verifies if the attribute is a well-formed value for "llvm.struct_attrs"
-    static LogicalResult verifyStructAttr(
-        Operation *op, Attribute attr, Type annotatedType);
-
     /// Verifies if the given string is a well-formed data layout descriptor.
     /// Uses `reportError` to report errors.
     static LogicalResult verifyDataLayoutString(

diff  --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
index 6ff52566dee3f..f70cb469f3f38 100644
--- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
+++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
@@ -78,54 +78,26 @@ static void filterFuncAttributes(func::FuncOp func, bool filterArgAndResAttrs,
   }
 }
 
-/// Helper function for wrapping all attributes into a single DictionaryAttr
-static auto wrapAsStructAttrs(OpBuilder &b, ArrayAttr attrs) {
-  return DictionaryAttr::get(
-      b.getContext(),
-      b.getNamedAttr(LLVM::LLVMDialect::getStructAttrsAttrName(), attrs));
-}
+/// Adds a an empty set of argument attributes for the newly added argument in
+/// front of the existing ones.
+static void prependEmptyArgAttr(OpBuilder &builder,
+                                SmallVectorImpl<NamedAttribute> &newFuncAttrs,
+                                func::FuncOp func) {
+  auto argAttrs = func.getArgAttrs();
+  // Nothing to do when there were no arg attrs beforehand.
+  if (!argAttrs)
+    return;
 
-/// Combines all result attributes into a single DictionaryAttr
-/// and prepends to argument attrs.
-/// This is intended to be used to format the attributes for a C wrapper
-/// function when the result(s) is converted to the first function argument
-/// (in the multiple return case, all returns get wrapped into a single
-/// argument). The total number of argument attributes should be equal to
-/// (number of function arguments) + 1.
-static void
-prependResAttrsToArgAttrs(OpBuilder &builder,
-                          SmallVectorImpl<NamedAttribute> &attributes,
-                          func::FuncOp func) {
   size_t numArguments = func.getNumArguments();
-  auto allAttrs = SmallVector<Attribute>(
-      numArguments + 1, DictionaryAttr::get(builder.getContext()));
-  NamedAttribute *argAttrs = nullptr;
-  for (auto *it = attributes.begin(); it != attributes.end();) {
-    if (it->getName() == func.getArgAttrsAttrName()) {
-      auto arrayAttrs = it->getValue().cast<ArrayAttr>();
-      assert(arrayAttrs.size() == numArguments &&
-             "Number of arg attrs and args should match");
-      std::copy(arrayAttrs.begin(), arrayAttrs.end(), allAttrs.begin() + 1);
-      argAttrs = it;
-    } else if (it->getName() == func.getResAttrsAttrName()) {
-      auto arrayAttrs = it->getValue().cast<ArrayAttr>();
-      assert(!arrayAttrs.empty() && "expected array to be non-empty");
-      allAttrs[0] = (arrayAttrs.size() == 1)
-                        ? arrayAttrs[0]
-                        : wrapAsStructAttrs(builder, arrayAttrs);
-      it = attributes.erase(it);
-      continue;
-    }
-    it++;
-  }
-
-  auto newArgAttrs = builder.getNamedAttr(func.getArgAttrsAttrName(),
-                                          builder.getArrayAttr(allAttrs));
-  if (!argAttrs) {
-    attributes.emplace_back(newArgAttrs);
-    return;
-  }
-  *argAttrs = newArgAttrs;
+  SmallVector<Attribute> newArgAttrs;
+  newArgAttrs.reserve(numArguments + 1);
+  // Insert empty dictionary for the new argument.
+  newArgAttrs.push_back(builder.getDictionaryAttr({}));
+
+  llvm::append_range(newArgAttrs, *argAttrs);
+  auto newNamedAttr = builder.getNamedAttr(func.getArgAttrsAttrName(),
+                                           builder.getArrayAttr(newArgAttrs));
+  newFuncAttrs.push_back(newNamedAttr);
 }
 
 /// Creates an auxiliary function with pointer-to-memref-descriptor-struct
@@ -141,12 +113,16 @@ static void wrapForExternalCallers(OpBuilder &rewriter, Location loc,
                                    func::FuncOp funcOp,
                                    LLVM::LLVMFuncOp newFuncOp) {
   auto type = funcOp.getFunctionType();
-  SmallVector<NamedAttribute, 4> attributes;
-  filterFuncAttributes(funcOp, /*filterArgAndResAttrs=*/false, attributes);
   auto [wrapperFuncType, resultIsNowArg] =
       typeConverter.convertFunctionTypeCWrapper(type);
+
+  SmallVector<NamedAttribute, 4> attributes;
+  // Only modify the argument and result attributes when the result is now an
+  // argument.
   if (resultIsNowArg)
-    prependResAttrsToArgAttrs(rewriter, attributes, funcOp);
+    prependEmptyArgAttr(rewriter, attributes, funcOp);
+  filterFuncAttributes(funcOp, /*filterArgAndResAttrs=*/resultIsNowArg,
+                       attributes);
   auto wrapperFuncOp = rewriter.create<LLVM::LLVMFuncOp>(
       loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
       wrapperFuncType, LLVM::Linkage::External, /*dsoLocal*/ false,
@@ -207,10 +183,13 @@ static void wrapExternalFunction(OpBuilder &builder, Location loc,
   assert(wrapperType && "unexpected type conversion failure");
 
   SmallVector<NamedAttribute, 4> attributes;
-  filterFuncAttributes(funcOp, /*filterArgAndResAttrs=*/false, attributes);
-
+  // Only modify the argument and result attributes when the result is now an
+  // argument.
   if (resultIsNowArg)
-    prependResAttrsToArgAttrs(builder, attributes, funcOp);
+    prependEmptyArgAttr(builder, attributes, funcOp);
+  filterFuncAttributes(funcOp, /*filterArgAndResAttrs=*/resultIsNowArg,
+                       attributes);
+
   // Create the auxiliary function.
   auto wrapperFunc = builder.create<LLVM::LLVMFuncOp>(
       loc, llvm::formatv("_mlir_ciface_{0}", funcOp.getName()).str(),
@@ -312,8 +291,7 @@ struct FuncOpConversionBase : public ConvertOpToLLVMPattern<func::FuncOp> {
       auto newResAttrDicts =
           (funcOp.getNumResults() == 1)
               ? resAttrDicts
-              : rewriter.getArrayAttr(
-                    {wrapAsStructAttrs(rewriter, resAttrDicts)});
+              : rewriter.getArrayAttr(rewriter.getDictionaryAttr({}));
       attributes.push_back(
           rewriter.getNamedAttr(funcOp.getResAttrsAttrName(), newResAttrDicts));
     }

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 8eb861c477cb8..79e39e18cbc0e 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -3018,12 +3018,6 @@ LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
     }
   }
 
-  if (attr.getName() == LLVMDialect::getStructAttrsAttrName()) {
-    return op->emitOpError()
-           << "'" << LLVM::LLVMDialect::getStructAttrsAttrName()
-           << "' is permitted only in argument or result attributes";
-  }
-
   // If the data layout attribute is present, it must use the LLVM data layout
   // syntax. Try parsing it and report errors in case of failure. Users of this
   // attribute may assume it is well-formed and can pass it to the (asserting)
@@ -3040,46 +3034,6 @@ LogicalResult LLVMDialect::verifyOperationAttribute(Operation *op,
                            << "' to be a string attributes";
 }
 
-LogicalResult LLVMDialect::verifyStructAttr(Operation *op, Attribute attr,
-                                            Type annotatedType) {
-  auto structType = annotatedType.dyn_cast<LLVMStructType>();
-  if (!structType) {
-    const auto emitIncorrectAnnotatedType = [&op]() {
-      return op->emitError()
-             << "expected '" << LLVMDialect::getStructAttrsAttrName()
-             << "' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'";
-    };
-    const auto ptrType = annotatedType.dyn_cast<LLVMPointerType>();
-    if (!ptrType)
-      return emitIncorrectAnnotatedType();
-    structType = ptrType.getElementType().dyn_cast<LLVMStructType>();
-    if (!structType)
-      return emitIncorrectAnnotatedType();
-  }
-
-  const auto arrAttrs = attr.dyn_cast<ArrayAttr>();
-  if (!arrAttrs)
-    return op->emitError() << "expected '"
-                           << LLVMDialect::getStructAttrsAttrName()
-                           << "' to be an array attribute";
-
-  if (structType.getBody().size() != arrAttrs.size())
-    return op->emitError()
-           << "size of '" << LLVMDialect::getStructAttrsAttrName()
-           << "' must match the size of the annotated '!llvm.struct'";
-  return success();
-}
-
-static LogicalResult verifyFuncOpInterfaceStructAttr(Operation *op,
-                                                     Attribute attr,
-                                                     Type annotatedType) {
-  if (isa<FunctionOpInterface>(op))
-    return LLVMDialect::verifyStructAttr(op, attr, annotatedType);
-  return op->emitError() << "expected '"
-                         << LLVMDialect::getStructAttrsAttrName()
-                         << "' to be used on function-like operations";
-}
-
 LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op,
                                                     Type paramType,
                                                     NamedAttribute paramAttr) {
@@ -3131,10 +3085,6 @@ LogicalResult LLVMDialect::verifyParameterAttribute(Operation *op,
     return success();
   };
 
-  // Note: The struct parameter attributes are not lowered to LLVM IR.
-  if (name == LLVMDialect::getStructAttrsAttrName())
-    return verifyFuncOpInterfaceStructAttr(op, paramAttr.getValue(), paramType);
-
   // Check a unit attribute that is attached to a pointer value.
   if (name == LLVMDialect::getNoAliasAttrName() ||
       name == LLVMDialect::getReadonlyAttrName() ||

diff  --git a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-callers.mlir b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-callers.mlir
index 8b9360a099001..826ca9540ae56 100644
--- a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-callers.mlir
+++ b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-callers.mlir
@@ -2,7 +2,7 @@
 
 // CHECK: llvm.func @res_attrs_with_memref_return() -> (!llvm.struct{{.*}} {test.returnOne})
 // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_memref_return
-// CHECK: %{{.*}}: !llvm.ptr{{.*}} {test.returnOne}
+// CHECK-NOT: test.returnOne
 func.func @res_attrs_with_memref_return() -> (memref<f32> {test.returnOne}) {
   %0 = memref.alloc() : memref<f32>
   return %0 : memref<f32>
@@ -10,24 +10,30 @@ func.func @res_attrs_with_memref_return() -> (memref<f32> {test.returnOne}) {
 
 // CHECK: llvm.func @res_attrs_with_value_return() -> (f32 {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_value_return
-// CHECK: -> (f32 {test.returnOne = 1 : i64})
+// CHECK-SAME: -> (f32 {test.returnOne = 1 : i64})
 func.func @res_attrs_with_value_return() -> (f32 {test.returnOne = 1}) {
   %0 = arith.constant 1.00 : f32
   return %0 : f32
 }
 
-// CHECK: llvm.func @multiple_return() -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_return() -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return
-// CHECK: (%{{.*}}: !llvm.ptr<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-NOT: test.returnThree
 func.func @multiple_return() -> (memref<f32> {test.returnOne = 1}, f32 {test.returnTwo = 2, test.returnThree = 3}) {
   %0 = memref.alloc() : memref<f32>
   %1 = arith.constant 1.00 : f32
   return %0, %1 : memref<f32>, f32
 }
 
-// CHECK: llvm.func @multiple_return_missing_res_attr() -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_return_missing_res_attr() -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return_missing_res_attr
-// CHECK: (%{{.*}}: !llvm.ptr<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-NOT: test.returnThree
 func.func @multiple_return_missing_res_attr() -> (memref<f32> {test.returnOne = 1}, i64, f32 {test.returnTwo = 2, test.returnThree = 3}) {
   %0 = memref.alloc() : memref<f32>
   %1 = arith.constant 2 : i64
@@ -37,7 +43,9 @@ func.func @multiple_return_missing_res_attr() -> (memref<f32> {test.returnOne =
 
 // CHECK: llvm.func @one_arg_attr_no_res_attrs_with_memref_return({{.*}}) -> !llvm.struct{{.*}}
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_no_res_attrs_with_memref_return
-// CHECK: %{{.*}}: !llvm.ptr<{{.*}}>, %{{.*}}: !llvm.ptr<{{.*}}> {test.argOne = 1 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64})
 func.func @one_arg_attr_no_res_attrs_with_memref_return(%arg0: memref<f32> {test.argOne = 1}) -> memref<f32> {
   %0 = memref.alloc() : memref<f32>
   return %0 : memref<f32>
@@ -45,7 +53,10 @@ func.func @one_arg_attr_no_res_attrs_with_memref_return(%arg0: memref<f32> {test
 
 // CHECK: llvm.func @one_arg_attr_one_res_attr_with_memref_return({{.*}}) -> (!llvm.struct<{{.*}}> {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_memref_return
-// CHECK: (%{{.*}}: !llvm.ptr<{{.*}}> {test.returnOne = 1 : i64}, %{{.*}}: !llvm.ptr<{{.*}}> {test.argOne = 1 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64})
 func.func @one_arg_attr_one_res_attr_with_memref_return(%arg0: memref<f32> {test.argOne = 1}) -> (memref<f32> {test.returnOne = 1}) {
   %0 = memref.alloc() : memref<f32>
   return %0 : memref<f32>
@@ -53,15 +64,23 @@ func.func @one_arg_attr_one_res_attr_with_memref_return(%arg0: memref<f32> {test
 
 // CHECK: llvm.func @one_arg_attr_one_res_attr_with_value_return({{.*}}) -> (f32 {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_value_return
-// CHECK: (%{{.*}}: !llvm.ptr<{{.*}}> {test.argOne = 1 : i64}) -> (f32 {test.returnOne = 1 : i64})
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64})
+// CHECK-SAME: -> (f32 {test.returnOne = 1 : i64})
 func.func @one_arg_attr_one_res_attr_with_value_return(%arg0: memref<f32> {test.argOne = 1}) -> (f32 {test.returnOne = 1}) {
   %0 = arith.constant 1.00 : f32
   return %0 : f32
 }
 
-// CHECK: llvm.func @multiple_arg_attr_multiple_res_attr({{.*}}) -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{}, {test.returnOne = 1 : i64}, {test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_arg_attr_multiple_res_attr({{.*}}) -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_arg_attr_multiple_res_attr
-// CHECK: (%{{.*}}: !llvm.ptr<{{.*}}> {llvm.struct_attrs = [{}, {test.returnOne = 1 : i64}, {test.returnTwo = 2 : i64}]}, %{{.*}}: !llvm.ptr<{{.*}}> {test.argZero = 0 : i64}, %{{.*}}: f32, %{{.*}}: i32 {test.argTwo = 2 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argZero = 0 : i64}
+// CHECK-SAME: f32
+// CHECK-SAME: i32 {test.argTwo = 2 : i64})
 func.func @multiple_arg_attr_multiple_res_attr(%arg0: memref<f32> {test.argZero = 0}, %arg1: f32, %arg2: i32 {test.argTwo = 2}) -> (f32, memref<i32> {test.returnOne = 1}, i32 {test.returnTwo = 2}) {
   %0 = arith.constant 1.00 : f32
   %1 = memref.alloc() : memref<i32>
@@ -71,8 +90,8 @@ func.func @multiple_arg_attr_multiple_res_attr(%arg0: memref<f32> {test.argZero
 
 // CHECK: llvm.func @drop_linkage_attr() -> (!llvm.struct{{.*}} {test.returnOne})
 // CHECK-LABEL: llvm.func @_mlir_ciface_drop_linkage_attr
+// CHECK-SAME: !llvm.ptr
 // CHECK-NOT: llvm.linkage
-// CHECK: %{{.*}}: !llvm.ptr{{.*}} {test.returnOne}
 func.func @drop_linkage_attr() -> (memref<f32> {test.returnOne}) attributes { llvm.linkage = #llvm.linkage<external> } {
   %0 = memref.alloc() : memref<f32>
   return %0 : memref<f32>

diff  --git a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir
index 9d73072aab9d5..f43c23773d9de 100644
--- a/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir
+++ b/mlir/test/Conversion/FuncToLLVM/emit-c-wrappers-for-external-functions.mlir
@@ -2,46 +2,64 @@
 
 // CHECK: llvm.func @res_attrs_with_memref_return() -> (!llvm.struct{{.*}} {test.returnOne})
 // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_memref_return
-// CHECK: !llvm.ptr{{.*}} {test.returnOne}
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
 func.func private @res_attrs_with_memref_return() -> (memref<f32> {test.returnOne})
 
 // CHECK: llvm.func @res_attrs_with_value_return() -> (f32 {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_res_attrs_with_value_return
-// CHECK: -> (f32 {test.returnOne = 1 : i64})
+// CHECK-SAME: -> (f32 {test.returnOne = 1 : i64})
 func.func private @res_attrs_with_value_return() -> (f32 {test.returnOne = 1})
 
-// CHECK: llvm.func @multiple_return() -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_return() -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return
-// CHECK: (!llvm.ptr<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-NOT: test.returnThree
 func.func private @multiple_return() -> (memref<f32> {test.returnOne = 1}, f32 {test.returnTwo = 2, test.returnThree = 3})
 
-// CHECK: llvm.func @multiple_return_missing_res_attr() -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_return_missing_res_attr() -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_return_missing_res_attr
-// CHECK: (!llvm.ptr<{{.*}}> {llvm.struct_attrs = [{test.returnOne = 1 : i64}, {}, {test.returnThree = 3 : i64, test.returnTwo = 2 : i64}]})
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-NOT: test.returnThree
 func.func private @multiple_return_missing_res_attr() -> (memref<f32> {test.returnOne = 1}, i64, f32 {test.returnTwo = 2, test.returnThree = 3})
 
 // CHECK: llvm.func @one_arg_attr_no_res_attrs_with_memref_return({{.*}}) -> !llvm.struct{{.*}}
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_no_res_attrs_with_memref_return
-// CHECK: !llvm.ptr<{{.*}}>, !llvm.ptr<{{.*}}> {test.argOne = 1 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64})
 func.func private @one_arg_attr_no_res_attrs_with_memref_return(%arg0: memref<f32> {test.argOne = 1}) -> memref<f32>
 
 // CHECK: llvm.func @one_arg_attr_one_res_attr_with_memref_return({{.*}}) -> (!llvm.struct<{{.*}}> {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_memref_return
-// CHECK: (!llvm.ptr<{{.*}}> {test.returnOne = 1 : i64}, !llvm.ptr<{{.*}}> {test.argOne = 1 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64})
 func.func private @one_arg_attr_one_res_attr_with_memref_return(%arg0: memref<f32> {test.argOne = 1}) -> (memref<f32> {test.returnOne = 1})
 
 // CHECK: llvm.func @one_arg_attr_one_res_attr_with_value_return({{.*}}) -> (f32 {test.returnOne = 1 : i64})
 // CHECK-LABEL: llvm.func @_mlir_ciface_one_arg_attr_one_res_attr_with_value_return
-// CHECK: (!llvm.ptr<{{.*}}> {test.argOne = 1 : i64}) -> (f32 {test.returnOne = 1 : i64})
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argOne = 1 : i64}
+// CHECK-SAME: -> (f32 {test.returnOne = 1 : i64})
 func.func private @one_arg_attr_one_res_attr_with_value_return(%arg0: memref<f32> {test.argOne = 1}) -> (f32 {test.returnOne = 1})
 
-// CHECK: llvm.func @multiple_arg_attr_multiple_res_attr({{.*}}) -> (!llvm.struct<{{.*}}> {llvm.struct_attrs = [{}, {test.returnOne = 1 : i64}, {test.returnTwo = 2 : i64}]})
+// CHECK: llvm.func @multiple_arg_attr_multiple_res_attr({{.*}}) -> !llvm.struct<{{.*}}>
 // CHECK-LABEL: llvm.func @_mlir_ciface_multiple_arg_attr_multiple_res_attr
-// CHECK: (!llvm.ptr<{{.*}}> {llvm.struct_attrs = [{}, {test.returnOne = 1 : i64}, {test.returnTwo = 2 : i64}]}, !llvm.ptr<{{.*}}> {test.argZero = 0 : i64}, f32, i32 {test.argTwo = 2 : i64}
+// CHECK-SAME: !llvm.ptr
+// CHECK-NOT: test.returnOne
+// CHECK-NOT: test.returnTwo
+// CHECK-SAME: !llvm.ptr
+// CHECK-SAME: {test.argZero = 0 : i64}
+// CHECK-SAME: f32
+// CHECK-SAME: i32 {test.argTwo = 2 : i64})
 func.func private @multiple_arg_attr_multiple_res_attr(%arg0: memref<f32> {test.argZero = 0}, %arg1: f32, %arg2: i32 {test.argTwo = 2}) -> (f32, memref<i32> {test.returnOne = 1}, i32 {test.returnTwo = 2})
 
 // CHECK: llvm.func weak @drop_linkage_attr() -> (!llvm.struct{{.*}} {test.returnOne})
 // CHECK-LABEL: llvm.func @_mlir_ciface_drop_linkage_attr
+// CHECK-SAME: !llvm.ptr
 // CHECK-NOT: llvm.linkage
-// CHECK: !llvm.ptr{{.*}} {test.returnOne}
 func.func private @drop_linkage_attr() -> (memref<f32> {test.returnOne}) attributes { llvm.linkage = #llvm.linkage<weak> }

diff  --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir
index a425b240ba549..4547d13dc38b3 100644
--- a/mlir/test/Dialect/LLVMIR/invalid.mlir
+++ b/mlir/test/Dialect/LLVMIR/invalid.mlir
@@ -1247,69 +1247,6 @@ llvm.mlir.global internal @side_effecting_global() : !llvm.struct<(i8)> {
 
 // -----
 
-// expected-error at +1 {{'llvm.struct_attrs' is permitted only in argument or result attributes}}
-func.func @struct_attrs_in_op() attributes {llvm.struct_attrs = []} {
-  return
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'}}
-func.func @invalid_struct_attr_arg_type(%arg0 : i32 {llvm.struct_attrs = []}) {
-    return
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'}}
-func.func @invalid_struct_attr_pointer_arg_type(%arg0 : !llvm.ptr<i32> {llvm.struct_attrs = []}) {
-    return
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to be an array attribute}}
-func.func @invalid_arg_struct_attr_value(%arg0 : !llvm.struct<(i32)> {llvm.struct_attrs = {}}) {
-    return
-}
-
-// -----
-
-// expected-error at +1 {{size of 'llvm.struct_attrs' must match the size of the annotated '!llvm.struct'}}
-func.func @invalid_arg_struct_attr_size(%arg0 : !llvm.struct<(i32)> {llvm.struct_attrs = []}) {
-    return
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'}}
-func.func @invalid_struct_attr_res_type(%arg0 : i32) -> (i32 {llvm.struct_attrs = []}) {
-  return %arg0 : i32
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to annotate '!llvm.struct' or '!llvm.ptr<struct<...>>'}}
-func.func @invalid_struct_attr_pointer_res_type(%arg0 : !llvm.ptr<i32>) -> (!llvm.ptr<i32> {llvm.struct_attrs = []}) {
-    return %arg0 : !llvm.ptr<i32>
-}
-
-// -----
-
-// expected-error at +1 {{expected 'llvm.struct_attrs' to be an array attribute}}
-func.func @invalid_res_struct_attr_value(%arg0 : !llvm.struct<(i32)>) -> (!llvm.struct<(i32)> {llvm.struct_attrs = {}}) {
-    return %arg0 : !llvm.struct<(i32)>
-}
-
-// -----
-
-// expected-error at +1 {{size of 'llvm.struct_attrs' must match the size of the annotated '!llvm.struct'}}
-func.func @invalid_res_struct_attr_size(%arg0 : !llvm.struct<(i32)>) -> (!llvm.struct<(i32)> {llvm.struct_attrs = []}) {
-    return %arg0 : !llvm.struct<(i32)>
-}
-
-// -----
-
 func.func @insert_vector_invalid_source_vector_size(%arg0 : vector<16385xi8>, %arg1 : vector<[16]xi8>) {
   // expected-error at +1 {{op failed to verify that vectors are not bigger than 2^17 bits.}}
   %0 = llvm.intr.vector.insert %arg0, %arg1[0] : vector<16385xi8> into vector<[16]xi8>


        


More information about the Mlir-commits mailing list