Skip to content

Commit 9ae0a6e

Browse files
committed
[FLANG] Lower groupprivate to omp mlir
1 parent 826461b commit 9ae0a6e

4 files changed

Lines changed: 193 additions & 10 deletions

File tree

flang/include/flang/Lower/OpenMP.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ void genOpenMPSymbolProperties(AbstractConverter &converter,
8282
const pft::Variable &var);
8383

8484
void genThreadprivateOp(AbstractConverter &, const pft::Variable &);
85+
void genGroupprivateOp(AbstractConverter &, const pft::Variable &);
8586
void genDeclareTargetIntGlobal(AbstractConverter &, const pft::Variable &);
8687
bool isOpenMPTargetConstruct(const parser::OpenMPConstruct &);
8788
bool isOpenMPDeviceDeclareTarget(Fortran::lower::AbstractConverter &,

flang/lib/Lower/OpenMP/OpenMP.cpp

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,91 @@ static void threadPrivatizeVars(lower::AbstractConverter &converter,
692692
}
693693
}
694694

695+
static void groupprivatizeVars(lower::AbstractConverter &converter,
696+
lower::pft::Evaluation &eval) {
697+
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
698+
mlir::Location currentLocation = converter.getCurrentLocation();
699+
mlir::OpBuilder::InsertionGuard guard(firOpBuilder);
700+
firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
701+
702+
auto module = converter.getModuleOp();
703+
704+
// Create a groupprivate operation for the symbol.
705+
// TODO: Extract device_type from the groupprivate directive.
706+
auto genGroupprivateOp = [&](const semantics::Symbol &sym) -> mlir::Value {
707+
std::string globalName = converter.mangleName(sym);
708+
fir::GlobalOp global = module.lookupSymbol<fir::GlobalOp>(globalName);
709+
if (!global) {
710+
return mlir::Value();
711+
}
712+
713+
// Generate fir.address_of to get the global address
714+
mlir::Value symAddr = fir::AddrOfOp::create(
715+
firOpBuilder, currentLocation, global.resultType(), global.getSymbol());
716+
717+
mlir::omp::DeclareTargetDeviceType deviceTypeEnum =
718+
mlir::omp::DeclareTargetDeviceType::any;
719+
mlir::omp::DeclareTargetDeviceTypeAttr deviceTypeAttr =
720+
mlir::omp::DeclareTargetDeviceTypeAttr::get(firOpBuilder.getContext(),
721+
deviceTypeEnum);
722+
723+
return mlir::omp::GroupprivateOp::create(firOpBuilder, currentLocation,
724+
symAddr.getType(), symAddr,
725+
deviceTypeAttr);
726+
};
727+
728+
llvm::SetVector<const semantics::Symbol *> groupprivateSyms;
729+
converter.collectSymbolSet(eval, groupprivateSyms,
730+
semantics::Symbol::Flag::OmpGroupPrivate,
731+
/*collectSymbols=*/true,
732+
/*collectHostAssociatedSymbols=*/true);
733+
std::set<semantics::SourceName> groupprivateSymNames;
734+
735+
// For a COMMON block, the GroupprivateOp is generated for the block itself
736+
// instead of its members.
737+
llvm::SetVector<const semantics::Symbol *> commonSyms;
738+
739+
for (std::size_t i = 0; i < groupprivateSyms.size(); i++) {
740+
const semantics::Symbol *sym = groupprivateSyms[i];
741+
mlir::Value symGroupprivateValue;
742+
// The variable may be used more than once, and each reference has one
743+
// symbol with the same name. Only do once for references of one variable.
744+
if (groupprivateSymNames.find(sym->name()) != groupprivateSymNames.end())
745+
continue;
746+
groupprivateSymNames.insert(sym->name());
747+
748+
if (const semantics::Symbol *common =
749+
semantics::FindCommonBlockContaining(sym->GetUltimate())) {
750+
// Handle common block members: create groupprivate op for the entire
751+
// common block, then compute member offset.
752+
mlir::Value commonGroupprivateValue;
753+
if (commonSyms.contains(common)) {
754+
commonGroupprivateValue = converter.getSymbolAddress(*common);
755+
} else {
756+
commonGroupprivateValue = genGroupprivateOp(*common);
757+
if (!commonGroupprivateValue)
758+
continue;
759+
converter.bindSymbol(*common, commonGroupprivateValue);
760+
commonSyms.insert(common);
761+
}
762+
symGroupprivateValue = lower::genCommonBlockMember(
763+
converter, currentLocation, sym->GetUltimate(),
764+
commonGroupprivateValue, common->size());
765+
} else {
766+
symGroupprivateValue = genGroupprivateOp(*sym);
767+
}
768+
769+
if (!symGroupprivateValue) {
770+
continue;
771+
}
772+
773+
fir::ExtendedValue sexv = converter.getSymbolExtendedValue(*sym);
774+
fir::ExtendedValue symGroupprivateExv =
775+
getExtendedValue(sexv, symGroupprivateValue);
776+
converter.bindSymbol(*sym, symGroupprivateExv);
777+
}
778+
}
779+
695780
static mlir::Operation *setLoopVar(lower::AbstractConverter &converter,
696781
mlir::Location loc, mlir::Value indexVal,
697782
const semantics::Symbol *sym) {
@@ -1230,6 +1315,10 @@ static void createBodyOfOp(mlir::Operation &op, const OpWithBodyGenInfo &info,
12301315
}
12311316
}
12321317

1318+
if (info.dir == llvm::omp::Directive::OMPD_teams) {
1319+
groupprivatizeVars(info.converter, info.eval);
1320+
}
1321+
12331322
if (!info.genSkeletonOnly) {
12341323
if (ConstructQueue::const_iterator next = std::next(item);
12351324
next != queue.end()) {
@@ -2736,6 +2825,11 @@ genTargetOp(lower::AbstractConverter &converter, lower::SymMap &symTable,
27362825
!symbolsWithDynamicSubstring.contains(&sym.GetUltimate()))
27372826
return;
27382827

2828+
// Skip groupprivate symbols - they don't need to be mapped because
2829+
// groupprivate creates its own LDS storage.
2830+
if (sym.GetUltimate().test(semantics::Symbol::Flag::OmpGroupPrivate))
2831+
return;
2832+
27392833
if (!isDuplicateMappedSymbol(sym, dsp.getAllSymbolsToPrivatize(),
27402834
hasDeviceAddrSyms, mapSyms, isDevicePtrSyms)) {
27412835
if (const auto *details =
@@ -4015,7 +4109,8 @@ static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
40154109
semantics::SemanticsContext &semaCtx,
40164110
lower::pft::Evaluation &eval,
40174111
const parser::OpenMPGroupprivate &directive) {
4018-
TODO(converter.getCurrentLocation(), "GROUPPRIVATE");
4112+
// The groupprivate directive is lowered when the variable is referenced
4113+
// inside target/teams regions.
40194114
}
40204115

40214116
static void genOMP(lower::AbstractConverter &converter, lower::SymMap &symTable,
@@ -4419,6 +4514,9 @@ void Fortran::lower::genOpenMPSymbolProperties(
44194514

44204515
if (sym.test(semantics::Symbol::Flag::OmpDeclareTarget))
44214516
lower::genDeclareTargetIntGlobal(converter, var);
4517+
4518+
if (sym.test(semantics::Symbol::Flag::OmpGroupPrivate))
4519+
lower::genGroupprivateOp(converter, var);
44224520
}
44234521

44244522
void Fortran::lower::genThreadprivateOp(lower::AbstractConverter &converter,
@@ -4487,6 +4585,42 @@ void Fortran::lower::genThreadprivateOp(lower::AbstractConverter &converter,
44874585
converter.bindSymbol(sym, symThreadprivateExv);
44884586
}
44894587

4588+
void Fortran::lower::genGroupprivateOp(lower::AbstractConverter &converter,
4589+
const lower::pft::Variable &var) {
4590+
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
4591+
mlir::Location currentLocation = converter.getCurrentLocation();
4592+
4593+
const semantics::Symbol &sym = var.getSymbol();
4594+
4595+
// For common block members, the groupprivate op is generated for the entire
4596+
// common block in groupprivatizeVars, not for individual members here.
4597+
// The common block already has a global, so nothing to do here.
4598+
if (semantics::FindCommonBlockContaining(sym.GetUltimate())) {
4599+
return;
4600+
}
4601+
4602+
fir::GlobalOp global;
4603+
auto module = converter.getModuleOp();
4604+
std::string globalName = converter.mangleName(sym);
4605+
4606+
// Handle non-global variables - create a GlobalOp for them.
4607+
// Local variables with SAVE attribute can be groupprivate.
4608+
// Promote them to fir.global so that omp.groupprivate
4609+
// can reference them via fir.address_of.
4610+
if (!var.isGlobal()) {
4611+
if (module.lookupSymbol<fir::GlobalOp>(globalName))
4612+
global = module.lookupSymbol<fir::GlobalOp>(globalName);
4613+
else
4614+
global = globalInitialization(converter, firOpBuilder, sym, var,
4615+
currentLocation);
4616+
} else {
4617+
global = module.lookupSymbol<fir::GlobalOp>(globalName);
4618+
}
4619+
4620+
// The actual omp.groupprivate operation is created by groupprivatizeVars
4621+
// when entering a teams region.
4622+
}
4623+
44904624
// This function replicates threadprivate's behaviour of generating
44914625
// an internal fir.GlobalOp for non-global variables in the main program
44924626
// that have the implicit SAVE attribute, to simplifiy LLVM-IR and MLIR

flang/test/Lower/OpenMP/Todo/groupprivate.f90

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
!RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=60 %s -o - | FileCheck %s
2+
3+
! Test lowering of groupprivate directive to omp.groupprivate.
4+
5+
! CHECK-DAG: fir.global common @blk_
6+
! CHECK-DAG: fir.global @_QMmEx : i32
7+
8+
! Test: basic groupprivate with single variable
9+
10+
module m
11+
implicit none
12+
integer, save :: x
13+
!$omp groupprivate(x)
14+
end module
15+
16+
! CHECK-LABEL: func.func @_QPtest_groupprivate
17+
! CHECK: omp.target
18+
! CHECK: omp.teams
19+
! CHECK: fir.address_of(@_QMmEx)
20+
! CHECK: omp.groupprivate
21+
subroutine test_groupprivate()
22+
use m
23+
24+
!$omp target
25+
!$omp teams
26+
x = 10
27+
!$omp end teams
28+
!$omp end target
29+
end subroutine
30+
31+
! Test: groupprivate with common block
32+
module m2
33+
implicit none
34+
integer :: cb_x, cb_y
35+
real :: cb_z
36+
common /blk/ cb_x, cb_y, cb_z
37+
!$omp groupprivate(/blk/)
38+
end module
39+
40+
! CHECK-LABEL: func.func @_QPtest_common_block_groupprivate
41+
! CHECK: omp.target
42+
! CHECK: omp.teams
43+
! CHECK: fir.address_of(@blk_)
44+
! CHECK: omp.groupprivate
45+
! CHECK: fir.convert
46+
! CHECK: fir.coordinate_of
47+
subroutine test_common_block_groupprivate()
48+
use m2
49+
50+
!$omp target
51+
!$omp teams
52+
cb_x = 1
53+
cb_y = 2
54+
cb_z = 3.0
55+
!$omp end teams
56+
!$omp end target
57+
end subroutine

0 commit comments

Comments
 (0)