[flang-commits] [flang] [Flang] Preserve local host association attrs (PR #230001)

via flang-commits flang-commits at lists.llvm.org
Wed Oct 7 23:49:43 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: nudt_yixiao (keepyixiao)

<details>
<summary>Changes</summary>

Host-associated names may add VOLATILE or ASYNCHRONOUS locally, but lowering only considered attributes from the ultimate symbol.

Propagate local association attributes to hlfir.declare.

Add regression tests for global and tuple host associations.

Fixes: https://github.com/llvm/llvm-project/issues/208588

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


3 Files Affected:

- (modified) flang/lib/Lower/Bridge.cpp (+20) 
- (modified) flang/lib/Lower/ConvertVariable.cpp (+41-4) 
- (added) flang/test/Lower/volatile-host-association.f90 (+100) 


``````````diff
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 939d8d134552e..68b5a94bfcc6b 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -4617,6 +4617,26 @@ class FirConverter : public Fortran::lower::AbstractConverter {
         Fortran::lower::AggregateStoreMap storeMap;
         for (const Fortran::lower::pft::Variable &var :
              Fortran::lower::pft::getScopeVariableList(scope)) {
+          if (var.hasSymbol()) {
+            const Fortran::semantics::Symbol &sym = var.getSymbol();
+            if (const auto *hostDetails =
+                    sym.detailsIf<Fortran::semantics::HostAssocDetails>()) {
+              const Fortran::semantics::Symbol &hostSym = hostDetails->symbol();
+              const auto &attrs = sym.attrs();
+              const auto &hostAttrs = hostSym.attrs();
+              const bool addsAsynchronous =
+                  attrs.test(Fortran::semantics::Attr::ASYNCHRONOUS) &&
+                  !hostAttrs.test(Fortran::semantics::Attr::ASYNCHRONOUS);
+              const bool addsVolatile =
+                  attrs.test(Fortran::semantics::Attr::VOLATILE) &&
+                  !hostAttrs.test(Fortran::semantics::Attr::VOLATILE);
+              if (addsAsynchronous || addsVolatile) {
+                addSymbol(sym, getSymbolExtendedValue(hostSym, &localSymbols),
+                          /*forced=*/true);
+                continue;
+              }
+            }
+          }
           // Do no instantiate again variables from the block host
           // that appears in specification of block variables.
           if (!var.hasSymbol() || !lookupSymbol(var.getSymbol()))
diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp
index 59f46a31256fe..68653d641f93d 100644
--- a/flang/lib/Lower/ConvertVariable.cpp
+++ b/flang/lib/Lower/ConvertVariable.cpp
@@ -2550,6 +2550,45 @@ fir::FortranVariableFlagsAttr Fortran::lower::translateSymbolAttributes(
   return fir::FortranVariableFlagsAttr::get(mlirContext, flags);
 }
 
+/// Return attributes that apply to an associated name only in the current
+/// function scope. VOLATILE and ASYNCHRONOUS may be added to a host- or
+/// use-associated entity without changing the attributes of its ultimate
+/// symbol.
+static fir::FortranVariableFlagsEnum
+getLocalAssociationFlags(Fortran::lower::AbstractConverter &converter,
+                         const Fortran::semantics::Symbol &sym) {
+  fir::FortranVariableFlagsEnum flags = fir::FortranVariableFlagsEnum::None;
+  auto addFlags = [&](const Fortran::semantics::Symbol &localSym) {
+    const auto &attrs = localSym.attrs();
+    if (attrs.test(Fortran::semantics::Attr::ASYNCHRONOUS))
+      flags = flags | fir::FortranVariableFlagsEnum::asynchronous;
+    if (attrs.test(Fortran::semantics::Attr::VOLATILE))
+      flags = flags | fir::FortranVariableFlagsEnum::fortran_volatile;
+  };
+
+  if (sym.has<Fortran::semantics::HostAssocDetails>() ||
+      sym.has<Fortran::semantics::UseDetails>())
+    addFlags(sym);
+
+  const Fortran::lower::pft::FunctionLikeUnit *funit =
+      converter.getCurrentFunctionUnit();
+  if (!funit)
+    return flags;
+
+  const Fortran::semantics::Scope &scope = funit->getScope();
+  auto iter = scope.find(sym.name());
+  if (iter == scope.end())
+    return flags;
+  const Fortran::semantics::Symbol &localSym = *iter->second;
+  if ((!localSym.has<Fortran::semantics::HostAssocDetails>() &&
+       !localSym.has<Fortran::semantics::UseDetails>()) ||
+      &localSym.GetUltimate() != &sym.GetUltimate())
+    return flags;
+
+  addFlags(localSym);
+  return flags;
+}
+
 static bool
 isCapturedInInternalProcedure(Fortran::lower::AbstractConverter &converter,
                               const Fortran::semantics::Symbol &sym) {
@@ -2610,6 +2649,7 @@ static void genDeclareSymbol(Fortran::lower::AbstractConverter &converter,
       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
     if (converter.isVisibleCrayPointerTarget(sym))
       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::target;
+    extraFlags = extraFlags | getLocalAssociationFlags(converter, sym);
     fir::FortranVariableFlagsAttr attributes =
         Fortran::lower::translateSymbolAttributes(builder.getContext(), sym,
                                                   extraFlags);
@@ -2705,10 +2745,7 @@ void Fortran::lower::genDeclareSymbol(
     const mlir::Location loc = genLocation(converter, sym);
     if (isCapturedInInternalProcedure(converter, sym))
       extraFlags = extraFlags | fir::FortranVariableFlagsEnum::internal_assoc;
-    // FIXME: Using the ultimate symbol for translating symbol attributes will
-    // lead to situations where the VOLATILE/ASYNCHRONOUS attributes are not
-    // propagated to the hlfir.declare (these attributes can be added when
-    // using module variables).
+    extraFlags = extraFlags | getLocalAssociationFlags(converter, sym);
     fir::FortranVariableFlagsAttr attributes =
         Fortran::lower::translateSymbolAttributes(
             builder.getContext(), sym.GetUltimate(), extraFlags);
diff --git a/flang/test/Lower/volatile-host-association.f90 b/flang/test/Lower/volatile-host-association.f90
new file mode 100644
index 0000000000000..a20f93ab2189b
--- /dev/null
+++ b/flang/test/Lower/volatile-host-association.f90
@@ -0,0 +1,100 @@
+! RUN: bbc --strict-fir-volatile-verifier %s -o - | FileCheck %s
+
+! Verify that VOLATILE and ASYNCHRONOUS attributes added to a host-associated
+! name are reflected in the declaration inside the internal procedure without
+! changing the declaration in the host procedure.
+
+subroutine local_volatile_global
+  integer :: n = 0
+  call inner
+contains
+  subroutine inner
+    volatile :: n
+    do while (n == 0)
+    end do
+  end subroutine
+end subroutine
+
+! CHECK-LABEL: func.func @_QPlocal_volatile_global()
+! CHECK:         %[[ADDR:.*]] = fir.address_of(@_QFlocal_volatile_globalEn) : !fir.ref<i32>
+! CHECK-NOT:     fir.volatile_cast %[[ADDR]]
+! CHECK:         %[[HOST_DECLARE:.*]]:2 = hlfir.declare %[[ADDR]] uniq_name("_QFlocal_volatile_globalEn") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+
+! CHECK-LABEL: func.func private @_QFlocal_volatile_globalPinner()
+! CHECK:         %[[ADDR:.*]] = fir.address_of(@_QFlocal_volatile_globalEn) : !fir.ref<i32>
+! CHECK:         %[[VOLATILE_ADDR:.*]] = fir.volatile_cast %[[ADDR]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK:         %[[INNER_DECLARE:.*]]:2 = hlfir.declare %[[VOLATILE_ADDR]] uniq_name("_QFlocal_volatile_globalEn") fortran_attrs<volatile> : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK:         fir.load %[[INNER_DECLARE]]#0 : !fir.ref<i32, volatile>
+
+subroutine local_volatile_tuple
+  integer :: n
+  n = 0
+  call inner
+contains
+  subroutine inner
+    volatile :: n
+    do while (n == 0)
+    end do
+  end subroutine
+end subroutine
+
+! CHECK-LABEL: func.func @_QPlocal_volatile_tuple()
+! CHECK:         %[[HOST_ADDR:.*]] = fir.alloca i32
+! CHECK-NOT:     fir.volatile_cast %[[HOST_ADDR]]
+! CHECK:         %[[HOST_DECLARE:.*]]:2 = hlfir.declare %[[HOST_ADDR]] uniq_name("_QFlocal_volatile_tupleEn") fortran_attrs<internal_assoc> : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:         fir.call @_QFlocal_volatile_tuplePinner({{.*}}) {{.*}} : (!fir.ref<tuple<!fir.ref<i32>>>) -> ()
+
+! CHECK-LABEL: func.func private @_QFlocal_volatile_tuplePinner(
+! CHECK-SAME:    %[[HOST_TUPLE:.*]]: !fir.ref<tuple<!fir.ref<i32>>> {fir.host_assoc})
+! CHECK:         %[[COORD:.*]] = fir.coordinate_of %[[HOST_TUPLE]], {{.*}} : (!fir.ref<tuple<!fir.ref<i32>>>, i32) -> !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK:         %[[TUPLE_ADDR:.*]] = fir.load %[[COORD]] : !fir.llvm_ptr<!fir.ref<i32>>
+! CHECK:         %[[VOLATILE_ADDR:.*]] = fir.volatile_cast %[[TUPLE_ADDR]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK:         %[[INNER_DECLARE:.*]]:2 = hlfir.declare %[[VOLATILE_ADDR]] uniq_name("_QFlocal_volatile_tupleEn") fortran_attrs<volatile, host_assoc> : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK:         fir.load %[[INNER_DECLARE]]#0 : !fir.ref<i32, volatile>
+
+subroutine local_asynchronous_tuple
+  integer :: n
+  n = 0
+  call inner
+contains
+  subroutine inner
+    asynchronous :: n
+    n = n + 1
+  end subroutine
+end subroutine
+
+! CHECK-LABEL: func.func private @_QFlocal_asynchronous_tuplePinner(
+! CHECK:         %[[INNER_DECLARE:.*]]:2 = hlfir.declare {{.*}} uniq_name("_QFlocal_asynchronous_tupleEn") fortran_attrs<asynchronous, host_assoc>
+
+subroutine blk
+  integer :: n = 0
+  block
+    volatile :: n
+    do while (n == 0)
+    end do
+  end block
+end subroutine
+
+! CHECK-LABEL: func.func @_QPblk()
+! CHECK:         %[[ADDR:.*]] = fir.address_of(@_QFblkEn) : !fir.ref<i32>
+! CHECK:         %[[HOST_DECLARE:.*]]:2 = hlfir.declare %[[ADDR]] uniq_name("_QFblkEn") : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK:         %[[VOLATILE_ADDR:.*]] = fir.volatile_cast %[[HOST_DECLARE]]#0 : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK:         %[[BLOCK_DECLARE:.*]]:2 = hlfir.declare %[[VOLATILE_ADDR]] uniq_name("_QFblkEn") fortran_attrs<volatile> : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK:         fir.load %[[BLOCK_DECLARE]]#0 : !fir.ref<i32, volatile>
+
+module m
+  integer :: n = 0
+end module
+
+subroutine poll
+  use m
+  volatile :: n
+  do while (n == 0)
+  end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPpoll()
+! CHECK:         %[[ADDR:.*]] = fir.address_of(@_QMmEn) : !fir.ref<i32>
+! CHECK:         %[[VOLATILE_ADDR:.*]] = fir.volatile_cast %[[ADDR]] : (!fir.ref<i32>) -> !fir.ref<i32, volatile>
+! CHECK:         %[[DECLARE:.*]]:2 = hlfir.declare %[[VOLATILE_ADDR]] uniq_name("_QMmEn") fortran_attrs<volatile> : (!fir.ref<i32, volatile>) -> (!fir.ref<i32, volatile>, !fir.ref<i32, volatile>)
+! CHECK:         fir.load %[[DECLARE]]#0 : !fir.ref<i32, volatile>

``````````

</details>


https://github.com/llvm/llvm-project/pull/230001


More information about the flang-commits mailing list