diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td index 2ecbf8f50c50c..310db3f5f2179 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMTypes.td @@ -197,6 +197,10 @@ def LLVMStructType : LLVMType<"LLVMStruct", "struct", [ ArrayRef elements, bool isPacked = false); + static LLVMStructType getUniquedIdentified(MLIRContext *context, StringRef name, + ArrayRef elements, + bool isPacked = false); + /// Gets or creates a literal struct with the given body in the provided /// context. static LLVMStructType getLiteral(MLIRContext *context, ArrayRef types, diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp index d700dc52d42d2..7c6d00a6072f8 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypeSyntax.cpp @@ -249,9 +249,8 @@ Type LLVMStructType::parse(AsmParser &parser) { if (!isIdentified) return LLVMStructType::getLiteralChecked([loc] { return emitError(loc); }, loc.getContext(), {}, isPacked); - auto type = LLVMStructType::getIdentifiedChecked( - [loc] { return emitError(loc); }, loc.getContext(), name); - return trySetStructBody(type, {}, isPacked, parser, kwLoc); + auto type = LLVMStructType::getUniquedIdentified(loc.getContext(), name, {}, isPacked); + return type; } // Parse subtypes. For identified structs, put the identifier of the struct on @@ -272,9 +271,15 @@ Type LLVMStructType::parse(AsmParser &parser) { if (!isIdentified) return LLVMStructType::getLiteralChecked( [loc] { return emitError(loc); }, loc.getContext(), subtypes, isPacked); - auto type = LLVMStructType::getIdentifiedChecked( - [loc] { return emitError(loc); }, loc.getContext(), name); - return trySetStructBody(type, subtypes, isPacked, parser, subtypesLoc); + for (Type t : subtypes) { + if (!LLVMStructType::isValidElementType(t)) { + parser.emitError(subtypesLoc) + << "invalid LLVM structure element type: " << t; + return LLVMStructType(); + } + } + auto type = LLVMStructType::getUniquedIdentified(loc.getContext(), name, subtypes, isPacked); + return type; } /// Parses a type appearing inside another LLVM dialect-compatible type. This diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp index 8f39ede721c92..4c67711aab5da 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMTypes.cpp @@ -435,6 +435,22 @@ LLVMStructType LLVMStructType::getIdentifiedChecked( return Base::getChecked(emitError, context, name, /*opaque=*/false); } +LLVMStructType LLVMStructType::getUniquedIdentified(MLIRContext *context, + StringRef name, + ArrayRef elements, + bool isPacked) { + std::string stringName = name.str(); + unsigned counter = 1; + do { + auto type = LLVMStructType::getIdentified(context, stringName); + if (failed(type.setBody(elements, isPacked))) { + stringName = (Twine(name) + "." + Twine(counter++)).str(); + continue; + } + return type; + } while (true); +} + LLVMStructType LLVMStructType::getNewIdentified(MLIRContext *context, StringRef name, ArrayRef elements, diff --git a/mlir/test/Dialect/LLVMIR/struct_type_conflict.mlir b/mlir/test/Dialect/LLVMIR/struct_type_conflict.mlir new file mode 100644 index 0000000000000..700a5bc81e9b9 --- /dev/null +++ b/mlir/test/Dialect/LLVMIR/struct_type_conflict.mlir @@ -0,0 +1,29 @@ +// RUN: mlir-opt %s -o - | FileCheck %s + +module { + llvm.func @foo(%arg0: i32) -> i32 attributes {dso_local} { + %0 = llvm.mlir.constant(1 : i32) : i32 + %1 = llvm.mlir.constant(0 : i32) : i32 + // CHECK: !llvm.struct<"struct.S", (i32)> + %2 = llvm.alloca %0 x !llvm.struct<"struct.S", (i32)> {alignment = 4 : i64} : (i32) -> !llvm.ptr + %3 = llvm.getelementptr inbounds %2[%1, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.S", (i32)> + llvm.store %arg0, %3 {alignment = 4 : i64} : i32, !llvm.ptr + %4 = llvm.getelementptr inbounds %2[%1, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.S", (i32)> + %5 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32 + llvm.return %5 : i32 + } +} + +module { + llvm.func @getX(%arg0: !llvm.struct<"struct.S", (i32, i1, i32)>) -> i32 attributes {dso_local} { + %0 = llvm.mlir.constant(1 : i32) : i32 + %1 = llvm.mlir.constant(0 : i32) : i32 + // CHECK: !llvm.struct<"struct.S.1", (i32, i1, i32)> + %2 = llvm.alloca %0 x !llvm.struct<"struct.S", (i32, i1, i32)> {alignment = 4 : i64} : (i32) -> !llvm.ptr + %3 = llvm.getelementptr inbounds %2[%1, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.S", (i32, i1, i32)> + llvm.store %arg0, %3 {alignment = 4 : i64} : !llvm.struct<"struct.S", (i32, i1, i32)>, !llvm.ptr + %4 = llvm.getelementptr inbounds %2[%1, 0] : (!llvm.ptr, i32) -> !llvm.ptr, !llvm.struct<"struct.S", (i32, i1, i32)> + %5 = llvm.load %4 {alignment = 4 : i64} : !llvm.ptr -> i32 + llvm.return %5 : i32 + } +} diff --git a/mlir/test/Dialect/LLVMIR/types-invalid.mlir b/mlir/test/Dialect/LLVMIR/types-invalid.mlir index 76fb6780d8668..e723349ba5cdd 100644 --- a/mlir/test/Dialect/LLVMIR/types-invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/types-invalid.mlir @@ -1,4 +1,5 @@ // RUN: mlir-opt --allow-unregistered-dialect -split-input-file -verify-diagnostics %s +// REQUIRES: modified-named-struct-type-parser func.func @array_of_void() { // expected-error @+1 {{invalid array element type}}