[flang-commits] [flang] 603e5c8 - [flang][debug] Supply missing subprogram attributes (#181425)

via flang-commits flang-commits at lists.llvm.org
Fri Feb 20 13:23:06 PST 2026


Author: Tim
Date: 2026-02-20T21:23:01Z
New Revision: 603e5c832a5508e789316475cc0b8228de876f7c

URL: https://github.com/llvm/llvm-project/commit/603e5c832a5508e789316475cc0b8228de876f7c
DIFF: https://github.com/llvm/llvm-project/commit/603e5c832a5508e789316475cc0b8228de876f7c.diff

LOG: [flang][debug] Supply missing subprogram attributes (#181425)

Add DW_AT_elemental, DW_AT_pure, and DW_AT_recursive attributes to
subprograms and functions when they are specified in the source.

Added: 
    flang/test/Lower/HLFIR/recursive-user-procedure.f90
    flang/test/Transforms/debug-fn-attr.fir

Modified: 
    flang/include/flang/Optimizer/Dialect/FIRAttr.td
    flang/lib/Lower/CallInterface.cpp
    flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
    flang/test/Lower/OpenMP/declare-target-func-and-subr.f90
    flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90
    flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90
    flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Optimizer/Dialect/FIRAttr.td b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
index 2fbe195ee9f33..b23d28fdde55c 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRAttr.td
+++ b/flang/include/flang/Optimizer/Dialect/FIRAttr.td
@@ -77,12 +77,14 @@ def FIRfuncPure          : I32BitEnumAttrCaseBit<"pure", 1>;
 def FIRfuncNonRecursive  : I32BitEnumAttrCaseBit<"non_recursive", 2>;
 def FIRfuncSimple        : I32BitEnumAttrCaseBit<"simple", 3>;
 def FIRfuncBind_c        : I32BitEnumAttrCaseBit<"bind_c", 4>;
-
-def fir_FortranProcedureFlagsEnum : I32BitEnumAttr<
-    "FortranProcedureFlagsEnum",
-    "Fortran procedure attributes",
-    [FIRfuncNoAttributes, FIRfuncElemental, FIRfuncPure, FIRfuncNonRecursive,
-     FIRfuncSimple, FIRfuncBind_c]> {
+def FIRfuncRecursive : I32BitEnumAttrCaseBit<"recursive", 5>;
+
+def fir_FortranProcedureFlagsEnum
+    : I32BitEnumAttr<"FortranProcedureFlagsEnum",
+                     "Fortran procedure attributes",
+                     [FIRfuncNoAttributes, FIRfuncElemental, FIRfuncPure,
+                      FIRfuncNonRecursive, FIRfuncSimple, FIRfuncBind_c,
+                      FIRfuncRecursive]> {
   let separator = ", ";
   let cppNamespace = "::fir";
   let genSpecializedAttr = 0;

diff  --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp
index f5ae2de5cad8b..129f71a027451 100644
--- a/flang/lib/Lower/CallInterface.cpp
+++ b/flang/lib/Lower/CallInterface.cpp
@@ -1579,9 +1579,14 @@ Fortran::lower::CallInterface<T>::getProcedureAttrs(
       if (sym->attrs().test(Fortran::semantics::Attr::NON_RECURSIVE) ||
           (sym->owner().context().languageFeatures().IsEnabled(
                Fortran::common::LanguageFeature::DefaultSave) &&
-           !sym->attrs().test(Fortran::semantics::Attr::RECURSIVE))) {
+           !sym->attrs().test(Fortran::semantics::Attr::RECURSIVE)))
         flags = flags | fir::FortranProcedureFlagsEnum::non_recursive;
-      }
+
+      // Set RECURSIVE if the attribute is explicitly present.  This is only
+      // used for debug info generation to maintain consistency with pre-F2018
+      // compilers.
+      if (sym->attrs().test(Fortran::semantics::Attr::RECURSIVE))
+        flags = flags | fir::FortranProcedureFlagsEnum::recursive;
     }
   }
   if (flags != fir::FortranProcedureFlagsEnum::none)

diff  --git a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
index 42080dacc731a..63698fdb88909 100644
--- a/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
+++ b/flang/lib/Optimizer/Transforms/AddDebugInfo.cpp
@@ -565,6 +565,20 @@ void AddDebugInfoPass::handleFuncOp(mlir::func::FuncOp funcOp,
     subprogramFlags =
         subprogramFlags | mlir::LLVM::DISubprogramFlags::Definition;
   }
+
+  // Check if the function has the pure, elemental, or recursive procedure
+  // attribute
+  if (fir::hasProcedureAttr<fir::FortranProcedureFlagsEnum::pure>(funcOp))
+    subprogramFlags = subprogramFlags | mlir::LLVM::DISubprogramFlags::Pure;
+
+  if (fir::hasProcedureAttr<fir::FortranProcedureFlagsEnum::elemental>(funcOp))
+    subprogramFlags =
+        subprogramFlags | mlir::LLVM::DISubprogramFlags::Elemental;
+
+  if (fir::hasProcedureAttr<fir::FortranProcedureFlagsEnum::recursive>(funcOp))
+    subprogramFlags =
+        subprogramFlags | mlir::LLVM::DISubprogramFlags::Recursive;
+
   unsigned line = getLineFromLoc(l);
   if (fir::isInternalProcedure(funcOp)) {
     // For contained functions, the scope is the parent subroutine.

diff  --git a/flang/test/Lower/HLFIR/recursive-user-procedure.f90 b/flang/test/Lower/HLFIR/recursive-user-procedure.f90
new file mode 100644
index 0000000000000..cbbd1a260d429
--- /dev/null
+++ b/flang/test/Lower/HLFIR/recursive-user-procedure.f90
@@ -0,0 +1,8 @@
+! Test lowering of user-defined recursive function attribute
+! RUN: bbc -emit-hlfir -o - %s 2>&1 | FileCheck %s
+recursive integer function factorial(n)
+    implicit none
+    integer, intent(in) :: n
+end function factorial
+
+! CHECK: func.func @_QPfactorial{{.*}} attributes {fir.proc_attrs = #fir.proc_attrs<recursive>}

diff  --git a/flang/test/Lower/OpenMP/declare-target-func-and-subr.f90 b/flang/test/Lower/OpenMP/declare-target-func-and-subr.f90
index d6175dd8730c2..46465eece5050 100644
--- a/flang/test/Lower/OpenMP/declare-target-func-and-subr.f90
+++ b/flang/test/Lower/OpenMP/declare-target-func-and-subr.f90
@@ -161,7 +161,7 @@ SUBROUTINE SUBR_DEFAULT_EXTENDEDLIST()
 !! -----
 
 ! DEVICE-LABEL: func.func @_QPrecursive_declare_target
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}
 RECURSIVE FUNCTION RECURSIVE_DECLARE_TARGET(INCREMENT) RESULT(K)
 !$omp declare target to(RECURSIVE_DECLARE_TARGET) device_type(nohost)
     INTEGER :: INCREMENT, K
@@ -173,7 +173,7 @@ RECURSIVE FUNCTION RECURSIVE_DECLARE_TARGET(INCREMENT) RESULT(K)
 END FUNCTION RECURSIVE_DECLARE_TARGET
 
 ! DEVICE-LABEL: func.func @_QPrecursive_declare_target_enter
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter), automap = false>{{.*}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter), automap = false>{{.*}}
 RECURSIVE FUNCTION RECURSIVE_DECLARE_TARGET_ENTER(INCREMENT) RESULT(K)
 !$omp declare target enter(RECURSIVE_DECLARE_TARGET_ENTER) device_type(nohost)
     INTEGER :: INCREMENT, K

diff  --git a/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90 b/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90
index e8709f23c5413..2caa6ba0b5b1e 100644
--- a/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90
+++ b/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap-enter.f90
@@ -105,7 +105,7 @@ end function target_function_test_host
 !! -----
 
 ! DEVICE-LABEL: func.func @_QPimplicitly_captured_with_dev_type_recursive
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter), automap = false>{{.*}}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (enter), automap = false>{{.*}}}
 recursive function implicitly_captured_with_dev_type_recursive(increment) result(k)
 !$omp declare target enter(implicitly_captured_with_dev_type_recursive) device_type(host)
    integer :: increment, k
@@ -174,7 +174,7 @@ recursive subroutine implicitly_captured_recursive(increment)
 end program
 
 ! DEVICE-LABEL: func.func @_QPimplicitly_captured_recursive
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter), automap = false>{{.*}}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (enter), automap = false>{{.*}}}
 recursive subroutine implicitly_captured_recursive(increment)
    integer :: increment
    if (increment == 10) then

diff  --git a/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90 b/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90
index be1e5a0d31f4b..32a5058029174 100644
--- a/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90
+++ b/flang/test/Lower/OpenMP/declare-target-implicit-func-and-subr-cap.f90
@@ -131,7 +131,7 @@ end function target_function_test_host
 !! -----
 
 ! DEVICE-LABEL: func.func @_QPimplicitly_captured_with_dev_type_recursive
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (to), automap = false>{{.*}}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (to), automap = false>{{.*}}}
 recursive function implicitly_captured_with_dev_type_recursive(increment) result(k)
 !$omp declare target to(implicitly_captured_with_dev_type_recursive) device_type(host)
    integer :: increment, k
@@ -200,7 +200,7 @@ recursive subroutine implicitly_captured_recursive(increment)
 end program
 
 ! DEVICE-LABEL: func.func @_QPimplicitly_captured_recursive
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
 recursive subroutine implicitly_captured_recursive(increment)
    integer :: increment
    if (increment == 10) then

diff  --git a/flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90 b/flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90
index c1c1ea37fe471..c31bfd1e61e8e 100644
--- a/flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90
+++ b/flang/test/Lower/OpenMP/declare-target-implicit-tarop-cap.f90
@@ -67,7 +67,7 @@ end function target_function_test_device
 !! -----
 
 ! DEVICE-LABEL: func.func @_QPimplicitly_captured_recursive
-! DEVICE-SAME: {{.*}}attributes {omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
+! DEVICE-SAME: {{.*}}attributes {{.*}}omp.declare_target = #omp.declaretarget<device_type = (nohost), capture_clause = (to), automap = false>{{.*}}}
 recursive function implicitly_captured_recursive(increment) result(k)
    integer :: increment, k
    if (increment == 10) then

diff  --git a/flang/test/Transforms/debug-fn-attr.fir b/flang/test/Transforms/debug-fn-attr.fir
new file mode 100644
index 0000000000000..d6409e1402cce
--- /dev/null
+++ b/flang/test/Transforms/debug-fn-attr.fir
@@ -0,0 +1,17 @@
+// RUN: fir-opt --add-debug-info --mlir-print-debuginfo %s | FileCheck %s
+
+module {
+  func.func @_QPvector_magnitude() attributes {fir.proc_attrs = #fir.proc_attrs<pure>} {
+    return
+  }
+  func.func @_QPsquare() attributes {fir.proc_attrs = #fir.proc_attrs<elemental, pure>} {
+    return
+  }
+  func.func @_QPfactorial() attributes {fir.proc_attrs = #fir.proc_attrs<recursive>} {
+    return
+  }
+}
+
+// CHECK: #di_subprogram = #llvm.di_subprogram<{{.*}}, name = "vector_magnitude",{{.*}}subprogramFlags = "Definition|Pure"
+// CHECK: #di_subprogram1 = #llvm.di_subprogram<{{.*}}, name = "square",{{.*}}subprogramFlags = "Definition|Pure|Elemental"
+// CHECK: #di_subprogram2 = #llvm.di_subprogram<{{.*}}, name = "factorial",{{.*}}subprogramFlags = "Definition|Recursive"


        


More information about the flang-commits mailing list