Skip to content

[flang] Retain internal and BIND(C) host procedure link in FIR #87796

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 17, 2024

Conversation

jeanPerier
Copy link
Contributor

Currently, it is not possible to find back which fun.func is the host procedure of some internal procedure because the mangling of the internal procedure does not contain info about the BIND(C) name of the host.
This info may be useful to ensure dwarf DW_TAG_subprogram of internal procedures are nested under DW_TAG_subprogram of host procedures for instance.

Currently, it is not possible to find back which fun.func is the
host procedure of some internal procedure because the mangling
of the internal procedure does not contain info about the BIND(C)
name of the host.
This info may be useful to ensure dwarf DW_TAG_subprogram of internal
procedures are nested under DW_TAG_subprogram  of host procedures for
instance.
@jeanPerier jeanPerier requested review from Renaud-K and vzakhari April 5, 2024 15:40
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir labels Apr 5, 2024
@llvmbot
Copy link
Member

llvmbot commented Apr 5, 2024

@llvm/pr-subscribers-openacc
@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-fir-hlfir

Author: None (jeanPerier)

Changes

Currently, it is not possible to find back which fun.func is the host procedure of some internal procedure because the mangling of the internal procedure does not contain info about the BIND(C) name of the host.
This info may be useful to ensure dwarf DW_TAG_subprogram of internal procedures are nested under DW_TAG_subprogram of host procedures for instance.


Full diff: https://github.com/llvm/llvm-project/pull/87796.diff

3 Files Affected:

  • (modified) flang/include/flang/Optimizer/Dialect/FIROpsSupport.h (+7)
  • (modified) flang/lib/Lower/CallInterface.cpp (+15)
  • (added) flang/test/Lower/HLFIR/internal-procedures-bindc-host.f90 (+13)
diff --git a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
index 3266ea3aa7fdc6..c5dd21199676c3 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
+++ b/flang/include/flang/Optimizer/Dialect/FIROpsSupport.h
@@ -109,6 +109,13 @@ static constexpr llvm::StringRef getInternalProcedureAttrName() {
   return "fir.internal_proc";
 }
 
+/// Attribute to link an internal procedure to its host procedure symbol when
+/// the internal procedure mangled name does not allow retrieving the host
+/// func.func because the host is BIND(C).
+static constexpr llvm::StringRef getHostSymbolAttrName() {
+  return "fir.host_symbol";
+}
+
 /// Attribute containing the original name of a function from before the
 /// ExternalNameConverision pass runs
 static constexpr llvm::StringRef getInternalFuncNameAttrName() {
diff --git a/flang/lib/Lower/CallInterface.cpp b/flang/lib/Lower/CallInterface.cpp
index 29cdb3cff589ba..d3135ba34ee4b2 100644
--- a/flang/lib/Lower/CallInterface.cpp
+++ b/flang/lib/Lower/CallInterface.cpp
@@ -589,6 +589,21 @@ void Fortran::lower::CalleeInterface::setFuncAttrs(
 static void addSymbolAttribute(mlir::func::FuncOp func,
                                const Fortran::semantics::Symbol &sym,
                                mlir::MLIRContext &mlirContext) {
+  // The link between an internal procedure and its host procedure is lost
+  // in FIR if the host is BIND(C) since the internal mangling will not
+  // allow retrieving the host bind(C) name, and therefore func.func symbol.
+  // Preserve it as an attribute so that this can be later retrieved.
+  if (sym.owner().kind() == Fortran::semantics::Scope::Kind::Subprogram)
+    if (const Fortran::semantics::Symbol *hostProcedure = sym.owner().symbol())
+      if (Fortran::semantics::IsBindCProcedure(*hostProcedure)) {
+        std::string hostName = Fortran::lower::mangle::mangleName(
+            *hostProcedure, /*keepExternalInScope=*/true);
+        func->setAttr(
+            fir::getHostSymbolAttrName(),
+            mlir::SymbolRefAttr::get(
+                &mlirContext, mlir::StringAttr::get(&mlirContext, hostName)));
+      }
+
   // Only add this on bind(C) functions for which the symbol is not reflected in
   // the current context.
   if (!Fortran::semantics::IsBindCProcedure(sym))
diff --git a/flang/test/Lower/HLFIR/internal-procedures-bindc-host.f90 b/flang/test/Lower/HLFIR/internal-procedures-bindc-host.f90
new file mode 100644
index 00000000000000..cb7470ce92dc03
--- /dev/null
+++ b/flang/test/Lower/HLFIR/internal-procedures-bindc-host.f90
@@ -0,0 +1,13 @@
+! Test fir.host_sym attribute to retain link between internal
+! and host procedure in FIR even when BIND(C) is involved.
+
+! RUN: bbc -emit-hlfir -o - %s | FileCheck %s
+
+subroutine foo() bind(c, name="some_c_name")
+  call bar()
+contains
+ subroutine bar()
+ end subroutine
+end subroutine
+! CHECK: func.func @some_c_name()
+! CHECK: func.func private @_QFfooPbar() attributes {fir.host_symbol = @some_c_name, llvm.linkage = #llvm.linkage<internal>}

// Preserve it as an attribute so that this can be later retrieved.
if (sym.owner().kind() == Fortran::semantics::Scope::Kind::Subprogram)
if (const Fortran::semantics::Symbol *hostProcedure = sym.owner().symbol())
if (Fortran::semantics::IsBindCProcedure(*hostProcedure)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a suggestion: maybe we should just always set it for consistency. I think this should not affect readability of FIR too much.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback. Makes sense to me. It is also then possible to get rid of fir.internal_proc and just use the new attribute. I updated the patch to do it for all internal procedures, including the ones from the main programs, and removed fir.internal_proc.

@jeanPerier jeanPerier requested a review from vzakhari April 16, 2024 18:37
Copy link
Contributor

@vzakhari vzakhari left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you, Jean! Sorry for the delay, it went under the radar.

@jeanPerier
Copy link
Contributor Author

Thank you, Jean! Sorry for the delay, it went under the radar.

No problem, I am the one who took ages to update it, thanks for the review!

@jeanPerier jeanPerier merged commit 971237d into llvm:main Apr 17, 2024
@jeanPerier jeanPerier deleted the jpr_internal_proc_link branch April 17, 2024 09:31
@DominikAdamski
Copy link
Contributor

Hi,
Your PR breaks compilation of OpenMP Fortran code:

program test
use, intrinsic :: iso_fortran_env
implicit none
    integer, parameter :: n = 1024
    integer(int32) :: x(n),  y(n)
    integer :: i
    x = 1
    y = 0
    y = test_offload(x)
    do i = 1,n
      if ( x(i) .ne. y(i)) then
        stop 1
      endif
    enddo
    print *, "Test passed"

    contains
        function test_offload(xin) result(xout)
            integer(int32), intent(in) :: xin(1024)
            integer(int32) :: xout(1024)
            integer :: ii
            xout = 0.0
!$omp target parallel do map(to:xin) map(from: xout)
            do ii=1,1024
                xout(ii) = xin(ii)
            end do
!$omp end target parallel do
        end function test_offload
end program test

Compilation command:
flang-new -O2 -fopenmp --offload-arch=sm_70 test.f95 -o main

I observe ICE when flang-new tries to lower MLIR code to LLVM IR.

@jeanPerier
Copy link
Contributor Author

Hi, Your PR breaks compilation of OpenMP Fortran code:
I observe ICE when flang-new tries to lower MLIR code to LLVM IR.

Thanks, I could reproduce. The OMPFunctionFiltering assumed all function symbol uses are calls/address_of. When processing the host program (in the Fortran sense, not OpenMP) it now erases its internal procedures as if it were a call, and then proceeds to process the erased internal function, hence the segfault.

Working on a fix.

jeanPerier added a commit to jeanPerier/llvm-project that referenced this pull request Apr 23, 2024
jeanPerier added a commit that referenced this pull request Apr 24, 2024
The pass assumed that all fun.func symbol usages could be safely
replaced by undef, that is not true after #87796 that added a back link
from internal procedure back to the parent procedure. This caused the
internal procedures to be erased and then processed (segfault).

Also set visibility of such internal procedures so that MLIR do not remove them before
the target function is generated for the target region.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:fir-hlfir flang:openmp flang Flang issues not falling into any other category openacc
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants