================
@@ -239,33 +238,138 @@ class CanonicalizationOfOmp {
}
}
- void RewriteOmpAllocations(parser::ExecutionPart &body) {
- // Rewrite leading declarative allocations so they are nested
- // within their respective executable allocate directive
- //
- // Original:
- // ExecutionPartConstruct -> OpenMPDeclarativeAllocate
- // ExecutionPartConstruct -> OpenMPDeclarativeAllocate
- // ExecutionPartConstruct -> OpenMPExecutableAllocate
- //
- // After rewriting:
- // ExecutionPartConstruct -> OpenMPExecutableAllocate
- // ExecutionPartConstruct -> OpenMPDeclarativeAllocate
- // ExecutionPartConstruct -> OpenMPDeclarativeAllocate
- for (auto it = body.v.rbegin(); it != body.v.rend();) {
- if (auto *exec = GetOmpIf<parser::OpenMPExecutableAllocate>(*(it++))) {
- parser::OpenMPDeclarativeAllocate *decl;
- std::list<parser::OpenMPDeclarativeAllocate> subAllocates;
- while (it != body.v.rend() &&
- (decl = GetOmpIf<parser::OpenMPDeclarativeAllocate>(*it))) {
- subAllocates.push_front(std::move(*decl));
- it = decltype(it)(body.v.erase(std::next(it).base()));
+ // Canonicalization of allocate directives
+ //
+ // In OpenMP 5.0 and 5.1 the allocate directive could either be a declarative
+ // one or an executable one. As usual in such cases, this poses a problem
+ // when the directive appears at the boundary between the specification part
+ // and the execution part.
+ // The executable form can actually consist of several adjacent directives,
+ // whereas the declarative form is always standalone. Additionally, the
+ // executable form must be associated with an allocate statement.
+ //
+ // The parser tries to parse declarative statements first, so in the
+ // following case, the two directives will be declarative, even though
+ // they should be treated as a single executable form:
+ // integer, allocatable :: x, y ! Specification
+ // !$omp allocate(x)
+ // !$omp allocate(y)
+ // allocate(x, y) ! Execution
+ //
+ void CanonicalizeAllocateDirectives(parser::SpecificationPart &spec) {
+ auto found = blockForSpec_.find(&spec);
+ if (found == blockForSpec_.end()) {
+ // There is no corresponding execution part, so there is nothing to do.
+ return;
+ }
+ parser::Block &block = *found->second;
+
+ auto isAllocateStmt = [](const parser::ExecutionPartConstruct &epc) {
+ if (auto *ec = std::get_if<parser::ExecutableConstruct>(&epc.u)) {
+ if (auto *as =
+ std::get_if<parser::Statement<parser::ActionStmt>>(&ec->u)) {
+ return std::holds_alternative<
+ common::Indirection<parser::AllocateStmt>>(as->statement.u);
+ }
+ }
+ return false;
+ };
+
+ if (!block.empty() && isAllocateStmt(block.front())) {
+ // There are two places where an OpenMP declarative construct can
+ // show up in the tuple in specification part:
+ // (1) in std::list<OpenMPDeclarativeConstruct>, or
+ // (2) in std::list<DeclarationConstruct>.
+ // The case (1) is only possible is the list (2) is empty.
+
+ auto &omps =
+ std::get<std::list<parser::OpenMPDeclarativeConstruct>>(spec.t);
+ auto &decls = std::get<std::list<parser::DeclarationConstruct>>(spec.t);
+
+ if (!decls.empty()) {
+ MakeExecutableAllocateFromDecls(decls, block);
+ } else {
+ MakeExecutableAllocateFromOmps(omps, block);
+ }
+ }
+ }
+
+ parser::ExecutionPartConstruct EmbedInExec(
+ parser::OmpAllocateDirective *alo, parser::ExecutionPartConstruct &&epc)
{
+ // Nest current epc inside the allocate directive.
+ std::get<parser::Block>(alo->t).push_front(std::move(epc));
+ // Set the new epc to be the ExecutionPartConstruct made from
+ // the allocate directive.
+ parser::OpenMPConstruct opc(std::move(*alo));
+ common::Indirection<parser::OpenMPConstruct> ind(std::move(opc));
+ parser::ExecutableConstruct ec(std::move(ind));
+ return parser::ExecutionPartConstruct(std::move(ec));
+ }
+
+ void MakeExecutableAllocateFromDecls(
+ std::list<parser::DeclarationConstruct> &decls, parser::Block &body) {
+ using OpenMPDeclarativeConstruct =
+ common::Indirection<parser::OpenMPDeclarativeConstruct>;
+
+ auto getAllocate = [](parser::DeclarationConstruct *dc) {
+ if (auto *sc = std::get_if<parser::SpecificationConstruct>(&dc->u)) {
+ if (auto *odc = std::get_if<OpenMPDeclarativeConstruct>(&sc->u)) {
+ if (auto *alo =
+ std::get_if<parser::OmpAllocateDirective>(&odc->value().u)) {
+ return alo;
+ }
+ }
+ }
+ return static_cast<parser::OmpAllocateDirective *>(nullptr);
+ };
+
+ std::list<parser::DeclarationConstruct>::reverse_iterator rlast = [&]() {
+ for (auto rit = decls.rbegin(), rend = decls.rend(); rit != rend; ++rit)
{
----------------
Stylie777 wrote:
I am not sure rend is needed here, could it just be `rit != decls.rend()`
https://github.com/llvm/llvm-project/pull/165865
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits