[mlir] support recursive type conversion of named LLVM structs

A previous commit added support for converting elemental types contained in
LLVM dialect types in case they were not compatible with the LLVM dialect. It
was missing support for named structs as they could be recursive, which was not
supported by the conversion infra. Now that it is, add support for converting
such named structs.

Depends On D113579

Reviewed By: wsmoses

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

GitOrigin-RevId: 9dd1f8dfdd1a041ab48149de93b7f4a868ac4858
diff --git a/lib/Conversion/LLVMCommon/TypeConverter.cpp b/lib/Conversion/LLVMCommon/TypeConverter.cpp
index 5446aed..cd6651c 100644
--- a/lib/Conversion/LLVMCommon/TypeConverter.cpp
+++ b/lib/Conversion/LLVMCommon/TypeConverter.cpp
@@ -53,18 +53,43 @@
       return LLVM::LLVMPointerType::get(pointee, type.getAddressSpace());
     return llvm::None;
   });
-  addConversion([&](LLVM::LLVMStructType type) -> llvm::Optional<Type> {
-    // TODO: handle conversion of identified structs, which may be recursive.
-    if (type.isIdentified())
-      return type;
+  addConversion([&](LLVM::LLVMStructType type, SmallVectorImpl<Type> &results,
+                    ArrayRef<Type> callStack) -> llvm::Optional<LogicalResult> {
+    if (type.isIdentified()) {
+      auto convertedType = LLVM::LLVMStructType::getIdentified(
+          type.getContext(), ("_Converted_" + type.getName()).str());
+      unsigned counter = 1;
+      while (convertedType.isInitialized()) {
+        assert(counter != UINT_MAX &&
+               "about to overflow struct renaming counter in conversion");
+        convertedType = LLVM::LLVMStructType::getIdentified(
+            type.getContext(),
+            ("_Converted_" + std::to_string(counter) + type.getName()).str());
+      }
+      if (llvm::count(callStack, type) > 1) {
+        results.push_back(convertedType);
+        return success();
+      }
+
+      SmallVector<Type> convertedElemTypes;
+      convertedElemTypes.reserve(type.getBody().size());
+      if (failed(convertTypes(type.getBody(), convertedElemTypes)))
+        return llvm::None;
+
+      if (failed(convertedType.setBody(convertedElemTypes, type.isPacked())))
+        return failure();
+      results.push_back(convertedType);
+      return success();
+    }
 
     SmallVector<Type> convertedSubtypes;
     convertedSubtypes.reserve(type.getBody().size());
     if (failed(convertTypes(type.getBody(), convertedSubtypes)))
       return llvm::None;
 
-    return LLVM::LLVMStructType::getLiteral(type.getContext(),
-                                            convertedSubtypes, type.isPacked());
+    results.push_back(LLVM::LLVMStructType::getLiteral(
+        type.getContext(), convertedSubtypes, type.isPacked()));
+    return success();
   });
   addConversion([&](LLVM::LLVMArrayType type) -> llvm::Optional<Type> {
     if (auto element = convertType(type.getElementType()))
diff --git a/test/Conversion/StandardToLLVM/convert-types.mlir b/test/Conversion/StandardToLLVM/convert-types.mlir
index 8a15625..298ba1a 100644
--- a/test/Conversion/StandardToLLVM/convert-types.mlir
+++ b/test/Conversion/StandardToLLVM/convert-types.mlir
@@ -13,7 +13,7 @@
 func private @struct_ptr() -> !llvm.struct<(ptr<!test.smpla>)>
 
 // CHECK-LABEL: @named_struct_ptr()
-// CHECK: !llvm.struct<"named", (ptr<!test.smpla>)> 
+// CHECK: !llvm.struct<"_Converted_named", (ptr<i42>)>
 func private @named_struct_ptr() -> !llvm.struct<"named", (ptr<!test.smpla>)>
 
 // CHECK-LABEL: @array_ptr()
@@ -26,6 +26,6 @@
 
 // TODO: support conversion of recursive types in the conversion infra.
 // CHECK-LABEL: @named_recursive()
-// CHECK: !llvm.struct<"recursive", (ptr<!test.smpla>, ptr<struct<"recursive">>)> 
+// CHECK: !llvm.struct<"_Converted_recursive", (ptr<i42>, ptr<struct<"_Converted_recursive">>)>
 func private @named_recursive() -> !llvm.struct<"recursive", (ptr<!test.smpla>, ptr<struct<"recursive">>)>