[Flang][OpenMP] Extend omp requires detection in Bridge.cpp (#188106)

Currently, we do not check the module for requires directives, which
means we'll miss these and not set them on the OpenMP module.

Otherwise, due to the first come first serve method we currently check
the symbols, there is certain formats that would mean the compiler would
miss that a user had specified requires somewhere in the module. This is
partially but not fully avoided by the Semantics layer pushing the
requires on to the top most PFT symbol, as it is entirely possible to
create a legal Fortran program where you could have two or more of these
(e.g. module and main program in one file, standalone funcitons
intermixed with modules or main program). Some examples of this are
shown in the added Fortran test. This PR opts to resolve it by gathering
all of the relevant symbols and processing them.

Also removed gathering from BlockDataUnit as I don't think these symbols
ever get the requires applied.
This commit is contained in:
agozillon 2026-04-01 19:48:07 +02:00 committed by GitHub
parent fbf484009c
commit e55c85341d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 72 additions and 11 deletions

View File

@ -494,7 +494,8 @@ public:
// - Define module variables and OpenMP/OpenACC declarative constructs so
// they are available before lowering any function that may use them.
bool hasMainProgram = false;
const Fortran::semantics::Symbol *globalOmpRequiresSymbol = nullptr;
llvm::SmallVector<const Fortran::semantics::Symbol *>
globalOmpRequiresSymbols;
createBuilderOutsideOfFuncOpAndDo([&]() {
for (Fortran::lower::pft::Program::Units &u : pft.getUnits()) {
Fortran::common::visit(
@ -503,8 +504,7 @@ public:
if (f.isMainProgram())
hasMainProgram = true;
declareFunction(f);
if (!globalOmpRequiresSymbol)
globalOmpRequiresSymbol = f.getScope().symbol();
globalOmpRequiresSymbols.push_back(f.getScope().symbol());
},
[&](Fortran::lower::pft::ModuleLikeUnit &m) {
lowerModuleDeclScope(m);
@ -512,12 +512,15 @@ public:
m.containedUnitList)
if (auto *f =
std::get_if<Fortran::lower::pft::FunctionLikeUnit>(
&unit))
&unit)) {
declareFunction(*f);
globalOmpRequiresSymbols.push_back(
f->getScope().symbol());
}
globalOmpRequiresSymbols.push_back(m.getScope().symbol());
},
[&](Fortran::lower::pft::BlockDataUnit &b) {
if (!globalOmpRequiresSymbol)
globalOmpRequiresSymbol = b.symTab.symbol();
globalOmpRequiresSymbols.push_back(b.symTab.symbol());
},
[&](Fortran::lower::pft::CompilerDirectiveUnit &d) {},
[&](Fortran::lower::pft::OpenACCDirectiveUnit &d) {},
@ -567,7 +570,7 @@ public:
Fortran::common::LanguageFeature::Coarray));
});
finalizeOpenMPLowering(globalOmpRequiresSymbol);
finalizeOpenMPLowering(globalOmpRequiresSymbols);
}
/// Declare a function.
@ -7201,7 +7204,8 @@ private:
/// Performing OpenMP lowering actions that were deferred to the end of
/// lowering.
void finalizeOpenMPLowering(
const Fortran::semantics::Symbol *globalOmpRequiresSymbol) {
llvm::SmallVectorImpl<const Fortran::semantics::Symbol *>
&globalOmpRequiresSymbol) {
if (!ompDeferredDeclareTarget.empty()) {
bool deferredDeviceFuncFound =
Fortran::lower::markOpenMPDeferredDeclareTargetFunctions(
@ -7210,9 +7214,10 @@ private:
}
// Set the module attribute related to OpenMP requires directives
if (ompDeviceCodeFound)
Fortran::lower::genOpenMPRequires(getModuleOp().getOperation(),
globalOmpRequiresSymbol);
if (ompDeviceCodeFound) {
for (const Fortran::semantics::Symbol *sym : globalOmpRequiresSymbol)
Fortran::lower::genOpenMPRequires(getModuleOp().getOperation(), sym);
}
}
/// Record fir.dummy_scope operation for this function.

View File

@ -0,0 +1,56 @@
! RUN: split-file %s %t
! Verify that we pick up requires USM and apply it correctly when it is specified
! outside of the program.
! RUN: %flang_fc1 -emit-hlfir -fopenmp %t/requires-usm.f90 -o - | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %t/requires-usm.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -emit-hlfir %t/requires-usm.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -fopenmp-is-target-device -emit-hlfir %t/requires-usm.f90 -o - | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp %t/requires-usm-subroutine-after.f90 -o - | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %t/requires-usm-subroutine-after.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -emit-hlfir %t/requires-usm-subroutine-after.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -fopenmp-is-target-device -emit-hlfir %t/requires-usm-subroutine-after.f90 -o - | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp %t/requires-usm-program-after.f90 -o - | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-is-target-device %t/requires-usm-program-after.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -emit-hlfir %t/requires-usm-program-after.f90 -o - | FileCheck %s
! RUN: bbc -fopenmp -fopenmp-is-target-device -emit-hlfir %t/requires-usm-program-after.f90 -o - | FileCheck %s
! CHECK: module attributes {
! CHECK-SAME: omp.requires = #omp<clause_requires unified_shared_memory>
!--- requires-usm.f90
module declare_mod
implicit none
!$omp requires unified_shared_memory
contains
end module
program main
use declare_mod
implicit none
!$omp target
!$omp end target
end program
!--- requires-usm-subroutine-after.f90
program main
implicit none
end program main
subroutine test
!$omp requires unified_shared_memory
!$omp target
!$omp end target
end subroutine
!--- requires-usm-program-after.f90
subroutine test
end subroutine
program main
implicit none
!$omp requires unified_shared_memory
!$omp target
!$omp end target
end program main