Skip to content

[flang][OpenMP] Parse lastprivate modifier, add TODO to lowering #110568

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -522,6 +522,8 @@ class ParseTreeDumper {
NODE(parser, OmpEndSectionsDirective)
NODE(parser, OmpIfClause)
NODE_ENUM(OmpIfClause, DirectiveNameModifier)
NODE_ENUM(OmpLastprivateClause, LastprivateModifier)
NODE(parser, OmpLastprivateClause)
NODE(parser, OmpLinearClause)
NODE(OmpLinearClause, WithModifier)
NODE(OmpLinearClause, WithoutModifier)
Expand Down
9 changes: 9 additions & 0 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -3648,6 +3648,15 @@ struct OmpAtomicDefaultMemOrderClause {
OmpAtomicDefaultMemOrderClause, common::OmpAtomicDefaultMemOrderType);
};

// OMP 5.0 2.19.4.5 lastprivate-clause ->
// LASTPRIVATE ([lastprivate-modifier :] list)
// lastprivate-modifier -> CONDITIONAL
struct OmpLastprivateClause {
TUPLE_CLASS_BOILERPLATE(OmpLastprivateClause);
ENUM_CLASS(LastprivateModifier, Conditional);
std::tuple<std::optional<LastprivateModifier>, OmpObjectList> t;
};

// OpenMP Clauses
struct OmpClause {
UNION_CLASS_BOILERPLATE(OmpClause);
Expand Down
19 changes: 16 additions & 3 deletions flang/lib/Lower/OpenMP/Clauses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,9 +783,22 @@ IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp,

Lastprivate make(const parser::OmpClause::Lastprivate &inp,
semantics::SemanticsContext &semaCtx) {
// inp.v -> parser::OmpObjectList
return Lastprivate{{/*LastprivateModifier=*/std::nullopt,
/*List=*/makeObjects(inp.v, semaCtx)}};
// inp.v -> parser::OmpLastprivateClause
using wrapped = parser::OmpLastprivateClause;

CLAUSET_ENUM_CONVERT( //
convert, parser::OmpLastprivateClause::LastprivateModifier,
Lastprivate::LastprivateModifier,
// clang-format off
MS(Conditional, Conditional)
// clang-format on
);

auto &t0 = std::get<std::optional<wrapped::LastprivateModifier>>(inp.v.t);
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);

return Lastprivate{{/*LastprivateModifier=*/maybeApply(convert, t0),
/*List=*/makeObjects(t1, semaCtx)}};
}

Linear make(const parser::OmpClause::Linear &inp,
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Lower/OpenMP/DataSharingProcessor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ void DataSharingProcessor::collectSymbolsForPrivatization() {
explicitlyPrivatizedSymbols);
} else if (const auto &lastPrivateClause =
std::get_if<omp::clause::Lastprivate>(&clause.u)) {
lastprivateModifierNotSupported(*lastPrivateClause,
converter.getCurrentLocation());
const ObjectList &objects = std::get<ObjectList>(lastPrivateClause->t);
collectOmpObjectListSymbol(objects, explicitlyPrivatizedSymbols);
}
Expand Down
4 changes: 3 additions & 1 deletion flang/lib/Lower/OpenMP/OpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1554,7 +1554,9 @@ genSectionsOp(lower::AbstractConverter &converter, lower::SymMap &symTable,

for (const Clause &clause : item->clauses) {
if (clause.id == llvm::omp::Clause::OMPC_lastprivate) {
lastprivates.push_back(&std::get<clause::Lastprivate>(clause.u));
auto &lastp = std::get<clause::Lastprivate>(clause.u);
lastprivateModifierNotSupported(lastp, converter.getCurrentLocation());
lastprivates.push_back(&lastp);
} else {
switch (clause.id) {
case llvm::omp::Clause::OMPC_firstprivate:
Expand Down
13 changes: 13 additions & 0 deletions flang/lib/Lower/OpenMP/Utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <flang/Lower/ConvertType.h>
#include <flang/Lower/PFTBuilder.h>
#include <flang/Optimizer/Builder/FIRBuilder.h>
#include <flang/Optimizer/Builder/Todo.h>
#include <flang/Parser/parse-tree.h>
#include <flang/Parser/tools.h>
#include <flang/Semantics/tools.h>
Expand Down Expand Up @@ -356,6 +357,18 @@ semantics::Symbol *getOmpObjectSymbol(const parser::OmpObject &ompObject) {
return sym;
}

void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp,
mlir::Location loc) {
using Lastprivate = omp::clause::Lastprivate;
auto &maybeMod =
std::get<std::optional<Lastprivate::LastprivateModifier>>(lastp.t);
if (maybeMod) {
assert(*maybeMod == Lastprivate::LastprivateModifier::Conditional &&
"Unexpected lastprivate modifier");
TODO(loc, "lastprivate clause with CONDITIONAL modifier");
}
}

} // namespace omp
} // namespace lower
} // namespace Fortran
3 changes: 3 additions & 0 deletions flang/lib/Lower/OpenMP/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ void genObjectList(const ObjectList &objects,
lower::AbstractConverter &converter,
llvm::SmallVectorImpl<mlir::Value> &operands);

void lastprivateModifierNotSupported(const omp::clause::Lastprivate &lastp,
mlir::Location loc);

} // namespace omp
} // namespace lower
} // namespace Fortran
Expand Down
8 changes: 7 additions & 1 deletion flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,12 @@ TYPE_PARSER(construct<OmpOrderClause>(
TYPE_PARSER(
construct<OmpObject>(designator) || construct<OmpObject>("/" >> name / "/"))

// OMP 5.0 2.19.4.5 LASTPRIVATE ([lastprivate-modifier :] list)
TYPE_PARSER(construct<OmpLastprivateClause>(
maybe("CONDITIONAL" >>
pure(OmpLastprivateClause::LastprivateModifier::Conditional) / ":"),
Parser<OmpObjectList>{}))

TYPE_PARSER(
"ACQUIRE" >> construct<OmpClause>(construct<OmpClause::Acquire>()) ||
"ACQ_REL" >> construct<OmpClause>(construct<OmpClause::AcqRel>()) ||
Expand Down Expand Up @@ -289,7 +295,7 @@ TYPE_PARSER(
"IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
parenthesized(Parser<OmpObjectList>{}))) ||
"LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
parenthesized(Parser<OmpObjectList>{}))) ||
parenthesized(Parser<OmpLastprivateClause>{}))) ||
"LINEAR" >> construct<OmpClause>(construct<OmpClause::Linear>(
parenthesized(Parser<OmpLinearClause>{}))) ||
"LINK" >> construct<OmpClause>(construct<OmpClause::Link>(
Expand Down
8 changes: 8 additions & 0 deletions flang/lib/Parser/unparse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2067,6 +2067,12 @@ class UnparseVisitor {
},
x.u);
}
void Unparse(const OmpLastprivateClause &x) {
Walk(
std::get<std::optional<OmpLastprivateClause::LastprivateModifier>>(x.t),
":");
Walk(std::get<OmpObjectList>(x.t));
}
void Unparse(const OmpMapType::Always &) { Word("ALWAYS,"); }
void Unparse(const OmpMapClause &x) {
Walk(std::get<std::optional<OmpMapType>>(x.t), ":");
Expand Down Expand Up @@ -2764,6 +2770,8 @@ class UnparseVisitor {
WALK_NESTED_ENUM(OmpDefaultClause, Type) // OMP DEFAULT
WALK_NESTED_ENUM(OmpDefaultmapClause, ImplicitBehavior) // OMP DEFAULTMAP
WALK_NESTED_ENUM(OmpDefaultmapClause, VariableCategory) // OMP DEFAULTMAP
WALK_NESTED_ENUM(
OmpLastprivateClause, LastprivateModifier) // OMP lastprivate-modifier
WALK_NESTED_ENUM(OmpScheduleModifierType, ModType) // OMP schedule-modifier
WALK_NESTED_ENUM(OmpLinearModifier, Type) // OMP linear-modifier
WALK_NESTED_ENUM(OmpDependenceType, Type) // OMP dependence-type
Expand Down
40 changes: 28 additions & 12 deletions flang/lib/Semantics/check-omp-structure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3174,11 +3174,13 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_lastprivate);

CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v, "LASTPRIVATE");
const auto &objectList{std::get<parser::OmpObjectList>(x.v.t)};
CheckIsVarPartOfAnotherVar(
GetContext().clauseSource, objectList, "LASTPRIVATE");

DirectivesClauseTriple dirClauseTriple;
SymbolSourceMap currSymbols;
GetSymbolsInObjectList(x.v, currSymbols);
GetSymbolsInObjectList(objectList, currSymbols);
CheckDefinableObjects(currSymbols, GetClauseKindForParserClass(x));
CheckCopyingPolymorphicAllocatable(
currSymbols, llvm::omp::Clause::OMPC_lastprivate);
Expand All @@ -3193,6 +3195,21 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Lastprivate &x) {

CheckPrivateSymbolsInOuterCxt(
currSymbols, dirClauseTriple, GetClauseKindForParserClass(x));

using LastprivateModifier = parser::OmpLastprivateClause::LastprivateModifier;
const auto &maybeMod{std::get<std::optional<LastprivateModifier>>(x.v.t)};
if (maybeMod) {
unsigned version{context_.langOptions().OpenMPVersion};
unsigned allowedInVersion = 50;
if (version < allowedInVersion) {
std::string thisVersion{
std::to_string(version / 10) + "." + std::to_string(version % 10)};
context_.Say(GetContext().clauseSource,
"LASTPRIVATE clause with CONDITIONAL modifier is not "
"allowed in OpenMP v%s, try -fopenmp-version=%d"_err_en_US,
thisVersion, allowedInVersion);
}
}
}

void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) {
Expand Down Expand Up @@ -3617,18 +3634,17 @@ const parser::OmpObjectList *OmpStructureChecker::GetOmpObjectList(
const parser::OmpClause &clause) {

// Clauses with OmpObjectList as its data member
using MemberObjectListClauses =
std::tuple<parser::OmpClause::Copyprivate, parser::OmpClause::Copyin,
parser::OmpClause::Firstprivate, parser::OmpClause::From,
parser::OmpClause::Lastprivate, parser::OmpClause::Link,
parser::OmpClause::Private, parser::OmpClause::Shared,
parser::OmpClause::To, parser::OmpClause::Enter,
parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;
using MemberObjectListClauses = std::tuple<parser::OmpClause::Copyprivate,
parser::OmpClause::Copyin, parser::OmpClause::Firstprivate,
parser::OmpClause::From, parser::OmpClause::Link,
parser::OmpClause::Private, parser::OmpClause::Shared,
parser::OmpClause::To, parser::OmpClause::Enter,
parser::OmpClause::UseDevicePtr, parser::OmpClause::UseDeviceAddr>;

// Clauses with OmpObjectList in the tuple
using TupleObjectListClauses =
std::tuple<parser::OmpClause::Allocate, parser::OmpClause::Map,
parser::OmpClause::Reduction, parser::OmpClause::Aligned>;
using TupleObjectListClauses = std::tuple<parser::OmpClause::Allocate,
parser::OmpClause::Lastprivate, parser::OmpClause::Map,
parser::OmpClause::Reduction, parser::OmpClause::Aligned>;

// TODO:: Generate the tuples using TableGen.
// Handle other constructs with OmpObjectList such as OpenMPThreadprivate.
Expand Down
3 changes: 2 additions & 1 deletion flang/lib/Semantics/resolve-directives.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,8 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
return false;
}
bool Pre(const parser::OmpClause::Lastprivate &x) {
ResolveOmpObjectList(x.v, Symbol::Flag::OmpLastPrivate);
const auto &objList{std::get<parser::OmpObjectList>(x.v.t)};
ResolveOmpObjectList(objList, Symbol::Flag::OmpLastPrivate);
return false;
}
bool Pre(const parser::OmpClause::Copyin &x) {
Expand Down
12 changes: 12 additions & 0 deletions flang/test/Lower/OpenMP/Todo/lastprivate-conditional.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
! RUN: %not_todo_cmd bbc -emit-fir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s
! RUN: %not_todo_cmd %flang_fc1 -emit-fir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s

! CHECK: not yet implemented: lastprivate clause with CONDITIONAL modifier
subroutine foo()
integer :: x, i
x = 1
!$omp parallel do lastprivate(conditional: x)
do i = 1, 100
x = x + 1
enddo
end
54 changes: 54 additions & 0 deletions flang/test/Parser/OpenMP/lastprivate-clause.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
! RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=50 %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=50 %s | FileCheck --check-prefix="PARSE-TREE" %s

subroutine foo1()
integer :: x, i
x = 1
!$omp parallel do lastprivate(x)
do i = 1, 100
x = x + 1
enddo
end

!UNPARSE: SUBROUTINE foo1
!UNPARSE: INTEGER x, i
!UNPARSE: x=1_4
!UNPARSE: !$OMP PARALLEL DO LASTPRIVATE(x)
!UNPARSE: DO i=1_4,100_4
!UNPARSE: x=x+1_4
!UNPARSE: END DO
!UNPARSE: END SUBROUTINE

!PARSE-TREE: SubroutineStmt
!PARSE-TREE: Name = 'foo1'
!PARSE-TREE: OmpLoopDirective -> llvm::omp::Directive = parallel do
!PARSE-TREE: OmpClauseList -> OmpClause -> Lastprivate -> OmpLastprivateClause
!PARSE-TREE: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
!PARSE-TREE: EndSubroutineStmt


subroutine foo2()
integer :: x, i
x = 1
!$omp parallel do lastprivate(conditional: x)
do i = 1, 100
x = x + 1
enddo
end

!UNPARSE: SUBROUTINE foo2
!UNPARSE: INTEGER x, i
!UNPARSE: x=1_4
!UNPARSE: !$OMP PARALLEL DO LASTPRIVATE(CONDITIONAL:x)
!UNPARSE: DO i=1_4,100_4
!UNPARSE: x=x+1_4
!UNPARSE: END DO
!UNPARSE: END SUBROUTINE

!PARSE-TREE: SubroutineStmt
!PARSE-TREE: Name = 'foo2'
!PARSE-TREE: OmpLoopDirective -> llvm::omp::Directive = parallel do
!PARSE-TREE: OmpClauseList -> OmpClause -> Lastprivate -> OmpLastprivateClause
!PARSE-TREE: LastprivateModifier = Conditional
!PARSE-TREE: OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
!PARSE-TREE: EndSubroutineStmt
2 changes: 1 addition & 1 deletion llvm/include/llvm/Frontend/OpenMP/OMP.td
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ def OMPC_IsDevicePtr : Clause<"is_device_ptr"> {
}
def OMPC_LastPrivate : Clause<"lastprivate"> {
let clangClass = "OMPLastprivateClause";
let flangClass = "OmpObjectList";
let flangClass = "OmpLastprivateClause";
}
def OMPC_Linear : Clause<"linear"> {
let clangClass = "OMPLinearClause";
Expand Down
Loading