1 //===-- lib/Semantics/canonicalize-omp.cpp --------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "canonicalize-omp.h"
10 #include "flang/Parser/parse-tree-visitor.h"
12 // After Loop Canonicalization, rewrite OpenMP parse tree to make OpenMP
13 // Constructs more structured which provide explicit scopes for later
14 // structural checks and semantic analysis.
15 // 1. move structured DoConstruct and OmpEndLoopDirective into
16 // OpenMPLoopConstruct. Compilation will not proceed in case of errors
19 namespace Fortran::semantics
{
21 using namespace parser::literals
;
23 class CanonicalizationOfOmp
{
25 template <typename T
> bool Pre(T
&) { return true; }
26 template <typename T
> void Post(T
&) {}
27 CanonicalizationOfOmp(parser::Messages
&messages
) : messages_
{messages
} {}
29 void Post(parser::Block
&block
) {
30 for (auto it
{block
.begin()}; it
!= block
.end(); ++it
) {
31 if (auto *ompCons
{GetConstructIf
<parser::OpenMPConstruct
>(*it
)}) {
32 // OpenMPLoopConstruct
34 std::get_if
<parser::OpenMPLoopConstruct
>(&ompCons
->u
)}) {
35 RewriteOpenMPLoopConstruct(*ompLoop
, block
, it
);
37 } else if (auto *endDir
{
38 GetConstructIf
<parser::OmpEndLoopDirective
>(*it
)}) {
39 // Unmatched OmpEndLoopDirective
40 auto &dir
{std::get
<parser::OmpLoopDirective
>(endDir
->t
)};
41 messages_
.Say(dir
.source
,
42 "The %s directive must follow the DO loop associated with the "
43 "loop construct"_err_en_US
,
44 parser::ToUpperCaseLetters(dir
.source
.ToString()));
50 template <typename T
> T
*GetConstructIf(parser::ExecutionPartConstruct
&x
) {
51 if (auto *y
{std::get_if
<parser::ExecutableConstruct
>(&x
.u
)}) {
52 if (auto *z
{std::get_if
<common::Indirection
<T
>>(&y
->u
)}) {
59 void RewriteOpenMPLoopConstruct(parser::OpenMPLoopConstruct
&x
,
60 parser::Block
&block
, parser::Block::iterator it
) {
61 // Check the sequence of DoConstruct and OmpEndLoopDirective
62 // in the same iteration
65 // ExecutableConstruct -> OpenMPConstruct -> OpenMPLoopConstruct
66 // OmpBeginLoopDirective
67 // ExecutableConstruct -> DoConstruct
68 // ExecutableConstruct -> OmpEndLoopDirective (if available)
71 // ExecutableConstruct -> OpenMPConstruct -> OpenMPLoopConstruct
72 // OmpBeginLoopDirective
74 // OmpEndLoopDirective (if available)
75 parser::Block::iterator nextIt
;
76 auto &beginDir
{std::get
<parser::OmpBeginLoopDirective
>(x
.t
)};
77 auto &dir
{std::get
<parser::OmpLoopDirective
>(beginDir
.t
)};
80 if (++nextIt
!= block
.end()) {
81 if (auto *doCons
{GetConstructIf
<parser::DoConstruct
>(*nextIt
)}) {
82 if (doCons
->GetLoopControl()) {
84 std::get
<std::optional
<parser::DoConstruct
>>(x
.t
) =
86 nextIt
= block
.erase(nextIt
);
87 // try to match OmpEndLoopDirective
88 if (nextIt
!= block
.end()) {
90 GetConstructIf
<parser::OmpEndLoopDirective
>(*nextIt
)}) {
91 std::get
<std::optional
<parser::OmpEndLoopDirective
>>(x
.t
) =
97 messages_
.Say(dir
.source
,
98 "DO loop after the %s directive must have loop control"_err_en_US
,
99 parser::ToUpperCaseLetters(dir
.source
.ToString()));
101 return; // found do-loop
104 messages_
.Say(dir
.source
,
105 "A DO loop must follow the %s directive"_err_en_US
,
106 parser::ToUpperCaseLetters(dir
.source
.ToString()));
109 parser::Messages
&messages_
;
112 bool CanonicalizeOmp(parser::Messages
&messages
, parser::Program
&program
) {
113 CanonicalizationOfOmp omp
{messages
};
115 return !messages
.AnyFatalError();
117 } // namespace Fortran::semantics