[llvm] [flang][runtime] fix intrinsics case of extends_type_of (PR #161466)

Andre Kuhlenschmidt via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 1 13:51:37 PDT 2025


https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/161466

>From de9db9df1b319d3a617523e03d0c62ba9143e638 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 29 Sep 2025 17:17:56 -0700
Subject: [PATCH 1/5] initial commit

---
 .../include/flang-rt/runtime/descriptor.h     |  3 ++
 flang-rt/lib/runtime/derived-api.cpp          | 48 ++++++++++++-------
 flang-rt/lib/runtime/pointer.cpp              |  2 +-
 3 files changed, 35 insertions(+), 18 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/descriptor.h b/flang-rt/include/flang-rt/runtime/descriptor.h
index ff7ec050d32c7..d34eb326d39b7 100644
--- a/flang-rt/include/flang-rt/runtime/descriptor.h
+++ b/flang-rt/include/flang-rt/runtime/descriptor.h
@@ -227,6 +227,9 @@ class Descriptor {
   RT_API_ATTRS bool IsPointer() const {
     return raw_.attribute == CFI_attribute_pointer;
   }
+  RT_API_ATTRS bool IsAssociated() const {
+    return raw_.base_addr != nullptr;
+  }
   RT_API_ATTRS bool IsAllocatable() const {
     return raw_.attribute == CFI_attribute_allocatable;
   }
diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index bb08e0397fe9c..31b5333eace2f 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -118,29 +118,43 @@ bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) {
 }
 
 bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
+  // The wording of the standard indicates the order in which each case
+  // is checked. If performance becomes an issue, there are less maintainable
+  // versions of this code that would probably execute faster.
+  // F'23 16.9.86 p 5
+  // If MOLD is unlimited polymorphic and is either a disassociated pointer or
+  // unallocated allocatable variable, the result is true;
+  if ((mold.IsPointer() && !mold.IsAssociated()) || 
+      (mold.IsAllocatable() && !mold.IsAllocated())) {
+    return true;
+  } else if ((a.IsPointer() && !mold.IsAssociated()) ||
+      (a.IsAllocatable() && !a.IsAllocated())) {
+    return false;
+  }
   auto aType{a.raw().type};
   auto moldType{mold.raw().type};
-  if ((aType != CFI_type_struct && aType != CFI_type_other) ||
-      (moldType != CFI_type_struct && moldType != CFI_type_other)) {
-    // If either type is intrinsic, they must match.
-    return aType == moldType;
-  } else if (const typeInfo::DerivedType *
-      derivedTypeMold{GetDerivedType(mold)}) {
-    // If A is unlimited polymorphic and is either a disassociated pointer or
-    // unallocated allocatable, the result is false.
-    // Otherwise if the dynamic type of A or MOLD is extensible, the result is
-    // true if and only if the dynamic type of A is an extension type of the
-    // dynamic type of MOLD.
-    for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
-         derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
-      if (derivedTypeA == derivedTypeMold) {
-        return true;
+  if (aType == CFI_type_struct && moldType == CFI_type_struct) {
+    if (const auto *derivedTypeMold{GetDerivedType(mold)}) {
+      // Otherwise if the dynamic type of A or MOLD is extensible, the result is
+      // true if and only if the dynamic type of A is an extension type of the
+      // dynamic type of MOLD.
+      for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
+           derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
+          if (derivedTypeA == derivedTypeMold) {
+            return true;
+          }
       }
+      return false;
     }
-    return false;
-  } else {
     // MOLD is unlimited polymorphic and unallocated/disassociated.
+    // This might be impossible to reach since the case is now handled explicitly
+    // above.
     return true;
+  } else {
+    // F'23: otherwise, the result is processor dependent.
+    // extension, if types are not extensible, true if they match.
+    return aType != CFI_type_other && moldType != CFI_type_other && 
+      aType == moldType;
   }
 }
 
diff --git a/flang-rt/lib/runtime/pointer.cpp b/flang-rt/lib/runtime/pointer.cpp
index f8ada65541a1a..df72c052eaf93 100644
--- a/flang-rt/lib/runtime/pointer.cpp
+++ b/flang-rt/lib/runtime/pointer.cpp
@@ -259,7 +259,7 @@ int RTDEF(PointerDeallocatePolymorphic)(Descriptor &pointer,
 }
 
 bool RTDEF(PointerIsAssociated)(const Descriptor &pointer) {
-  return pointer.raw().base_addr != nullptr;
+  return pointer.IsAssociated();
 }
 
 bool RTDEF(PointerIsAssociatedWith)(

>From 05a86992ae61e4da6090b4f6989a01a91bb42cf4 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Tue, 30 Sep 2025 17:49:54 -0700
Subject: [PATCH 2/5] run clang format

---
 flang-rt/include/flang-rt/runtime/descriptor.h |  4 +---
 flang-rt/lib/runtime/derived-api.cpp           | 18 +++++++++---------
 2 files changed, 10 insertions(+), 12 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/descriptor.h b/flang-rt/include/flang-rt/runtime/descriptor.h
index d34eb326d39b7..d1a0eaaad7a3d 100644
--- a/flang-rt/include/flang-rt/runtime/descriptor.h
+++ b/flang-rt/include/flang-rt/runtime/descriptor.h
@@ -227,9 +227,7 @@ class Descriptor {
   RT_API_ATTRS bool IsPointer() const {
     return raw_.attribute == CFI_attribute_pointer;
   }
-  RT_API_ATTRS bool IsAssociated() const {
-    return raw_.base_addr != nullptr;
-  }
+  RT_API_ATTRS bool IsAssociated() const { return raw_.base_addr != nullptr; }
   RT_API_ATTRS bool IsAllocatable() const {
     return raw_.attribute == CFI_attribute_allocatable;
   }
diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index 31b5333eace2f..bca4fe76c1864 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -124,7 +124,7 @@ bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
   // F'23 16.9.86 p 5
   // If MOLD is unlimited polymorphic and is either a disassociated pointer or
   // unallocated allocatable variable, the result is true;
-  if ((mold.IsPointer() && !mold.IsAssociated()) || 
+  if ((mold.IsPointer() && !mold.IsAssociated()) ||
       (mold.IsAllocatable() && !mold.IsAllocated())) {
     return true;
   } else if ((a.IsPointer() && !mold.IsAssociated()) ||
@@ -139,22 +139,22 @@ bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
       // true if and only if the dynamic type of A is an extension type of the
       // dynamic type of MOLD.
       for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
-           derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
-          if (derivedTypeA == derivedTypeMold) {
-            return true;
-          }
+          derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
+        if (derivedTypeA == derivedTypeMold) {
+          return true;
+        }
       }
       return false;
     }
     // MOLD is unlimited polymorphic and unallocated/disassociated.
-    // This might be impossible to reach since the case is now handled explicitly
-    // above.
+    // This might be impossible to reach since the case is now handled
+    // explicitly above.
     return true;
   } else {
     // F'23: otherwise, the result is processor dependent.
     // extension, if types are not extensible, true if they match.
-    return aType != CFI_type_other && moldType != CFI_type_other && 
-      aType == moldType;
+    return aType != CFI_type_other && moldType != CFI_type_other &&
+        aType == moldType;
   }
 }
 

>From f360deca5b549ac0249e00cb56e5100f05016c2f Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 1 Oct 2025 10:29:25 -0700
Subject: [PATCH 3/5] fixing typo in pointer check of object

---
 flang-rt/lib/runtime/derived-api.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index bca4fe76c1864..d531822abb9dd 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -127,7 +127,7 @@ bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
   if ((mold.IsPointer() && !mold.IsAssociated()) ||
       (mold.IsAllocatable() && !mold.IsAllocated())) {
     return true;
-  } else if ((a.IsPointer() && !mold.IsAssociated()) ||
+  } else if ((a.IsPointer() && !a.IsAssociated()) ||
       (a.IsAllocatable() && !a.IsAllocated())) {
     return false;
   }

>From d61ea033e5162d52a81f5d7a95f981906d018109 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 1 Oct 2025 13:10:10 -0700
Subject: [PATCH 4/5] address feedback

---
 flang-rt/include/flang-rt/runtime/descriptor.h | 1 -
 flang-rt/lib/runtime/derived-api.cpp           | 6 ++----
 flang-rt/lib/runtime/pointer.cpp               | 2 +-
 3 files changed, 3 insertions(+), 6 deletions(-)

diff --git a/flang-rt/include/flang-rt/runtime/descriptor.h b/flang-rt/include/flang-rt/runtime/descriptor.h
index d1a0eaaad7a3d..ff7ec050d32c7 100644
--- a/flang-rt/include/flang-rt/runtime/descriptor.h
+++ b/flang-rt/include/flang-rt/runtime/descriptor.h
@@ -227,7 +227,6 @@ class Descriptor {
   RT_API_ATTRS bool IsPointer() const {
     return raw_.attribute == CFI_attribute_pointer;
   }
-  RT_API_ATTRS bool IsAssociated() const { return raw_.base_addr != nullptr; }
   RT_API_ATTRS bool IsAllocatable() const {
     return raw_.attribute == CFI_attribute_allocatable;
   }
diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index d531822abb9dd..62be78a9449d8 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -124,11 +124,9 @@ bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
   // F'23 16.9.86 p 5
   // If MOLD is unlimited polymorphic and is either a disassociated pointer or
   // unallocated allocatable variable, the result is true;
-  if ((mold.IsPointer() && !mold.IsAssociated()) ||
-      (mold.IsAllocatable() && !mold.IsAllocated())) {
+  if ((mold.IsPointer() || mold.IsAllocatable()) && !mold.IsAllocated()) {
     return true;
-  } else if ((a.IsPointer() && !a.IsAssociated()) ||
-      (a.IsAllocatable() && !a.IsAllocated())) {
+  } else if ((a.IsPointer() || a.IsAllocatable()) && !a.IsAllocated()) {
     return false;
   }
   auto aType{a.raw().type};
diff --git a/flang-rt/lib/runtime/pointer.cpp b/flang-rt/lib/runtime/pointer.cpp
index df72c052eaf93..f8ada65541a1a 100644
--- a/flang-rt/lib/runtime/pointer.cpp
+++ b/flang-rt/lib/runtime/pointer.cpp
@@ -259,7 +259,7 @@ int RTDEF(PointerDeallocatePolymorphic)(Descriptor &pointer,
 }
 
 bool RTDEF(PointerIsAssociated)(const Descriptor &pointer) {
-  return pointer.IsAssociated();
+  return pointer.raw().base_addr != nullptr;
 }
 
 bool RTDEF(PointerIsAssociatedWith)(

>From 9c7fd93a97e7fc127f3028bea62a07ba97254b59 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 1 Oct 2025 13:51:14 -0700
Subject: [PATCH 5/5] simplifying further

---
 flang-rt/lib/runtime/derived-api.cpp | 45 ++++++++++++++--------------
 1 file changed, 22 insertions(+), 23 deletions(-)

diff --git a/flang-rt/lib/runtime/derived-api.cpp b/flang-rt/lib/runtime/derived-api.cpp
index 62be78a9449d8..2d0db9a01a787 100644
--- a/flang-rt/lib/runtime/derived-api.cpp
+++ b/flang-rt/lib/runtime/derived-api.cpp
@@ -118,41 +118,40 @@ bool RTDEF(SameTypeAs)(const Descriptor &a, const Descriptor &b) {
 }
 
 bool RTDEF(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
-  // The wording of the standard indicates the order in which each case
-  // is checked. If performance becomes an issue, there are less maintainable
-  // versions of this code that would probably execute faster.
+  // The wording of the standard indicates null or unallocated checks take
+  // precedence over the extension checks which take precedence over any
+  // compiler specific behavior.
   // F'23 16.9.86 p 5
   // If MOLD is unlimited polymorphic and is either a disassociated pointer or
   // unallocated allocatable variable, the result is true;
-  if ((mold.IsPointer() || mold.IsAllocatable()) && !mold.IsAllocated()) {
-    return true;
-  } else if ((a.IsPointer() || a.IsAllocatable()) && !a.IsAllocated()) {
-    return false;
-  }
   auto aType{a.raw().type};
   auto moldType{mold.raw().type};
-  if (aType == CFI_type_struct && moldType == CFI_type_struct) {
-    if (const auto *derivedTypeMold{GetDerivedType(mold)}) {
+  if ((aType != CFI_type_struct && aType != CFI_type_other) ||
+      (moldType != CFI_type_struct && moldType != CFI_type_other)) {
+    if (!mold.IsAllocated()) {
+      return true;
+    } else if (!a.IsAllocated()) {
+      return false;
+    } else {
+      // If either type is intrinsic and not a pointer or allocatable
+      // then they must match.
+      return aType == moldType;
+    }
+  // The following checks imply the pointer/allocatable cases above.
+  } else if (const auto *derivedTypeMold{GetDerivedType(mold)}) {
       // Otherwise if the dynamic type of A or MOLD is extensible, the result is
       // true if and only if the dynamic type of A is an extension type of the
       // dynamic type of MOLD.
-      for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
-          derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
-        if (derivedTypeA == derivedTypeMold) {
-          return true;
-        }
+    for (const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
+        derivedTypeA; derivedTypeA = derivedTypeA->GetParentType()) {
+      if (derivedTypeA == derivedTypeMold) {
+        return true;
       }
-      return false;
     }
+    return false;
+  } else {
     // MOLD is unlimited polymorphic and unallocated/disassociated.
-    // This might be impossible to reach since the case is now handled
-    // explicitly above.
     return true;
-  } else {
-    // F'23: otherwise, the result is processor dependent.
-    // extension, if types are not extensible, true if they match.
-    return aType != CFI_type_other && moldType != CFI_type_other &&
-        aType == moldType;
   }
 }
 



More information about the llvm-commits mailing list