[flang-commits] [flang] [Flang] Preserve local host association attrs (PR #230001)
via flang-commits
flang-commits at lists.llvm.org
Wed Oct 7 23:48:33 PDT 2026
https://github.com/keepyixiao created https://github.com/llvm/llvm-project/pull/230001
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
>From 1ab31920b20081f1ba7c57b354aa274097512c33 Mon Sep 17 00:00:00 2001
From: nudt_yixiao <1272950933 at qq.com>
Date: Wed, 7 Oct 2026 22:14:15 +0800
Subject: [PATCH] [Flang] Preserve local host association attrs
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.
---
flang/lib/Lower/Bridge.cpp | 20 ++++
flang/lib/Lower/ConvertVariable.cpp | 45 +++++++-
.../test/Lower/volatile-host-association.f90 | 100 ++++++++++++++++++
3 files changed, 161 insertions(+), 4 deletions(-)
create mode 100644 flang/test/Lower/volatile-host-association.f90
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>
More information about the flang-commits
mailing list