Skip to content

Commit

Permalink
[Flang][OpenMP][Lower] Program level implicit SAVE variable handling …
Browse files Browse the repository at this point in the history
…for declare target

This is an attempt at mimicing the method in which
threadprivate handles the following type of variables:

program main
  integer :: i
  !$omp declare target to(i)
end

Which essentially generates a GlobalOp for the variable (which
would normally only be an alloca) when it's instantiated. The
main difference is there is no operation generated within the
function, instead the declare target attribute is appended
later within handleDeclareTarget.

Reviewers: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D152037
  • Loading branch information
agozillon committed Jul 13, 2023
1 parent f648c9f commit e909a2c
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 28 deletions.
1 change: 1 addition & 0 deletions flang/include/flang/Lower/OpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ void genOpenMPDeclarativeConstruct(AbstractConverter &, pft::Evaluation &,
const parser::OpenMPDeclarativeConstruct &);
int64_t getCollapseValue(const Fortran::parser::OmpClauseList &clauseList);
void genThreadprivateOp(AbstractConverter &, const pft::Variable &);
void genDeclareTargetIntGlobal(AbstractConverter &, const pft::Variable &);
void genOpenMPReduction(AbstractConverter &,
const Fortran::parser::OmpClauseList &clauseList);

Expand Down
13 changes: 9 additions & 4 deletions flang/lib/Lower/Bridge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4013,10 +4013,15 @@ class FirConverter : public Fortran::lower::AbstractConverter {
void instantiateVar(const Fortran::lower::pft::Variable &var,
Fortran::lower::AggregateStoreMap &storeMap) {
Fortran::lower::instantiateVariable(*this, var, localSymbols, storeMap);
if (var.hasSymbol() &&
var.getSymbol().test(
Fortran::semantics::Symbol::Flag::OmpThreadprivate))
Fortran::lower::genThreadprivateOp(*this, var);
if (var.hasSymbol()) {
if (var.getSymbol().test(
Fortran::semantics::Symbol::Flag::OmpThreadprivate))
Fortran::lower::genThreadprivateOp(*this, var);

if (var.getSymbol().test(
Fortran::semantics::Symbol::Flag::OmpDeclareTarget))
Fortran::lower::genDeclareTargetIntGlobal(*this, var);
}
}

/// Start translation of a function.
Expand Down
77 changes: 53 additions & 24 deletions flang/lib/Lower/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2641,6 +2641,39 @@ void Fortran::lower::genOpenMPConstruct(
ompConstruct.u);
}

fir::GlobalOp globalInitialization(Fortran::lower::AbstractConverter &converter,
fir::FirOpBuilder &firOpBuilder,
const Fortran::semantics::Symbol &sym,
const Fortran::lower::pft::Variable &var,
mlir::Location currentLocation) {
mlir::Type ty = converter.genType(sym);
std::string globalName = converter.mangleName(sym);
mlir::StringAttr linkage = firOpBuilder.createInternalLinkage();
fir::GlobalOp global =
firOpBuilder.createGlobal(currentLocation, ty, globalName, linkage);

// Create default initialization for non-character scalar.
if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
mlir::Type baseAddrType = ty.dyn_cast<fir::BoxType>().getEleTy();
Fortran::lower::createGlobalInitialization(
firOpBuilder, global, [&](fir::FirOpBuilder &b) {
mlir::Value nullAddr =
b.createNullConstant(currentLocation, baseAddrType);
mlir::Value box =
b.create<fir::EmboxOp>(currentLocation, ty, nullAddr);
b.create<fir::HasValueOp>(currentLocation, box);
});
} else {
Fortran::lower::createGlobalInitialization(
firOpBuilder, global, [&](fir::FirOpBuilder &b) {
mlir::Value undef = b.create<fir::UndefOp>(currentLocation, ty);
b.create<fir::HasValueOp>(currentLocation, undef);
});
}

return global;
}

void Fortran::lower::genThreadprivateOp(
Fortran::lower::AbstractConverter &converter,
const Fortran::lower::pft::Variable &var) {
Expand Down Expand Up @@ -2670,30 +2703,9 @@ void Fortran::lower::genThreadprivateOp(
// variable in main program, and it has implicit SAVE attribute. Take it as
// with SAVE attribute, so to create GlobalOp for it to simplify the
// translation to LLVM IR.
mlir::Type ty = converter.genType(sym);
std::string globalName = converter.mangleName(sym);
mlir::StringAttr linkage = firOpBuilder.createInternalLinkage();
fir::GlobalOp global =
firOpBuilder.createGlobal(currentLocation, ty, globalName, linkage);

// Create default initialization for non-character scalar.
if (Fortran::semantics::IsAllocatableOrPointer(sym)) {
mlir::Type baseAddrType = ty.dyn_cast<fir::BoxType>().getEleTy();
Fortran::lower::createGlobalInitialization(
firOpBuilder, global, [&](fir::FirOpBuilder &b) {
mlir::Value nullAddr =
b.createNullConstant(currentLocation, baseAddrType);
mlir::Value box =
b.create<fir::EmboxOp>(currentLocation, ty, nullAddr);
b.create<fir::HasValueOp>(currentLocation, box);
});
} else {
Fortran::lower::createGlobalInitialization(
firOpBuilder, global, [&](fir::FirOpBuilder &b) {
mlir::Value undef = b.create<fir::UndefOp>(currentLocation, ty);
b.create<fir::HasValueOp>(currentLocation, undef);
});
}
fir::GlobalOp global = globalInitialization(converter, firOpBuilder, sym,
var, currentLocation);

mlir::Value symValue = firOpBuilder.create<fir::AddrOfOp>(
currentLocation, global.resultType(), global.getSymbol());
symThreadprivateValue = firOpBuilder.create<mlir::omp::ThreadprivateOp>(
Expand All @@ -2716,6 +2728,23 @@ void Fortran::lower::genThreadprivateOp(
converter.bindSymbol(sym, symThreadprivateExv);
}

// This function replicates threadprivate's behaviour of generating
// an internal fir.GlobalOp for non-global variables in the main program
// that have the implicit SAVE attribute, to simplifiy LLVM-IR and MLIR
// generation.
void Fortran::lower::genDeclareTargetIntGlobal(
Fortran::lower::AbstractConverter &converter,
const Fortran::lower::pft::Variable &var) {
if (!var.isGlobal()) {
// A non-global variable which can be in a declare target directive must
// be a variable in the main program, and it has the implicit SAVE
// attribute. We create a GlobalOp for it to simplify the translation to
// LLVM IR.
globalInitialization(converter, converter.getFirOpBuilder(),
var.getSymbol(), var, converter.getCurrentLocation());
}
}

void handleDeclareTarget(Fortran::lower::AbstractConverter &converter,
Fortran::lower::pft::Evaluation &eval,
const Fortran::parser::OpenMPDeclareTargetConstruct
Expand Down
12 changes: 12 additions & 0 deletions flang/test/Lower/OpenMP/omp-declare-target-program-var.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
!RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s
!RUN: %flang_fc1 -emit-fir -fopenmp -fopenmp-is-target-device %s -o - | FileCheck %s

PROGRAM main
! CHECK-DAG: %0 = fir.alloca f32 {bindc_name = "i", uniq_name = "_QFEi"}
REAL :: I
! CHECK-DAG: fir.global internal @_QFEi {omp.declare_target = #omp.declaretarget<device_type = (any), capture_clause = (to)>} : f32 {
! CHECK-DAG: %0 = fir.undefined f32
! CHECK-DAG: fir.has_value %0 : f32
! CHECK-DAG: }
!$omp declare target(I)
END

0 comments on commit e909a2c

Please sign in to comment.