From 063c5bc31b89d85aba9ea7c2aa0d2440ec468ed2 Mon Sep 17 00:00:00 2001 From: Nimish Mishra Date: Fri, 1 Oct 2021 00:41:57 +0530 Subject: [PATCH] [flang][OpenMP] Added OpenMP 5.0 specification based semantic checks for sections construct and test case for simd construct According to OpenMP 5.0 spec document, the following semantic restrictions have been dealt with in this patch. 1. [sections construct] Orphaned section directives are prohibited. That is, the section directives must appear within the sections construct and must not be encountered elsewhere in the sections region. Semantic checks for the following are not necessary, since use of orphaned section construct (i.e. without an enclosing sections directive) throws parser errors and control flow never reaches the semantic checking phase. Added a test case for the same. 2. [sections construct] Must be a structured block Added test case and made changes to branching logic 3. [simd construct] Must be a structured block / A program that branches in or out of a function with declare simd is non conforming 4. Fixed !$omp do's handling of unlabeled CYCLEs Reviewed By: kiranchandramohan Differential Revision: https://reviews.llvm.org/D108904 --- .../lib/Semantics/check-directive-structure.h | 44 +++++- flang/test/Semantics/omp-sections02.f90 | 137 ++++++++++++++++++ flang/test/Semantics/omp-sections03.f90 | 27 ++++ flang/test/Semantics/omp-simd01.f90 | 52 ++++--- 4 files changed, 241 insertions(+), 19 deletions(-) create mode 100644 flang/test/Semantics/omp-sections02.f90 create mode 100644 flang/test/Semantics/omp-sections03.f90 diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h index 6ef60230cca5..af10be44aef6 100644 --- a/flang/lib/Semantics/check-directive-structure.h +++ b/flang/lib/Semantics/check-directive-structure.h @@ -35,8 +35,8 @@ public: parser::CharBlock sourcePosition, D directive, std::string &&upperCaseDirName) : context_{context}, sourcePosition_{sourcePosition}, - upperCaseDirName_{std::move(upperCaseDirName)}, currentDirective_{ - directive} {} + upperCaseDirName_{std::move(upperCaseDirName)}, + currentDirective_{directive}, numDoConstruct_{0} {} template bool Pre(const T &) { return true; } template void Post(const T &) {} @@ -45,16 +45,34 @@ public: return true; } + bool Pre(const parser::DoConstruct &) { + numDoConstruct_++; + return true; + } + void Post(const parser::DoConstruct &) { numDoConstruct_--; } void Post(const parser::ReturnStmt &) { EmitBranchOutError("RETURN"); } void Post(const parser::ExitStmt &exitStmt) { if (const auto &exitName{exitStmt.v}) { CheckConstructNameBranching("EXIT", exitName.value()); + } else { + CheckConstructNameBranching("EXIT"); } } void Post(const parser::StopStmt &) { EmitBranchOutError("STOP"); } void Post(const parser::CycleStmt &cycleStmt) { if (const auto &cycleName{cycleStmt.v}) { CheckConstructNameBranching("CYCLE", cycleName.value()); + } else { + switch ((llvm::omp::Directive)currentDirective_) { + // exclude directives which do not need a check for unlabelled CYCLES + case llvm::omp::Directive::OMPD_do: + return; + case llvm::omp::Directive::OMPD_simd: + return; + default: + break; + } + CheckConstructNameBranching("CYCLE"); } } @@ -71,6 +89,14 @@ private: .Attach(sourcePosition_, GetEnclosingMsg()); } + inline void EmitUnlabelledBranchOutError(const char *stmt) { + context_ + .Say(currentStatementSourcePosition_, + "%s to construct outside of %s construct is not allowed"_err_en_US, + stmt, upperCaseDirName_) + .Attach(sourcePosition_, GetEnclosingMsg()); + } + void EmitBranchOutErrorWithName( const char *stmt, const parser::Name &toName) const { const std::string branchingToName{toName.ToString()}; @@ -102,11 +128,25 @@ private: } } + // Check branching for unlabelled CYCLES and EXITs + void CheckConstructNameBranching(const char *stmt) { + // found an enclosing looping construct for the unlabelled EXIT/CYCLE + if (numDoConstruct_ > 0) { + return; + } + // did not found an enclosing looping construct within the OpenMP/OpenACC + // directive + EmitUnlabelledBranchOutError(stmt); + return; + } + SemanticsContext &context_; parser::CharBlock currentStatementSourcePosition_; parser::CharBlock sourcePosition_; std::string upperCaseDirName_; D currentDirective_; + int numDoConstruct_; // tracks number of DoConstruct found AFTER encountering + // an OpenMP/OpenACC directive }; // Generic structure checker for directives/clauses language such as OpenMP diff --git a/flang/test/Semantics/omp-sections02.f90 b/flang/test/Semantics/omp-sections02.f90 new file mode 100644 index 000000000000..c1597804af6e --- /dev/null +++ b/flang/test/Semantics/omp-sections02.f90 @@ -0,0 +1,137 @@ +! RUN: %python %S/test_errors.py %s %flang -fopenmp +! OpenMP version 5.0.0 +! 2.8.1 sections construct +! The code enclosed in a sections construct must be a structured block. +program OmpConstructSections01 + use omp_lib + integer :: section_count = 0 + integer, parameter :: NT = 4 + print *, 'section_count', section_count +!ERROR: invalid branch into an OpenMP structured block +!ERROR: invalid branch into an OpenMP structured block +!ERROR: invalid branch into an OpenMP structured block + if (NT) 20, 30, 40 +!ERROR: invalid branch into an OpenMP structured block + goto 20 +!$omp sections + !$omp section + print *, "This is a single statement structured block" + !$omp section + open (10, file="random-file-name.txt", err=30) + !ERROR: invalid branch into an OpenMP structured block + !ERROR: invalid branch leaving an OpenMP structured block + open (10, file="random-file-name.txt", err=40) + !$omp section + section_count = section_count + 1 +20 print *, 'Entering into section' + call calledFromWithinSection() + print *, 'section_count', section_count + !$omp section + section_count = section_count + 1 + print *, 'section_count', section_count + !ERROR: invalid branch leaving an OpenMP structured block + goto 10 + !$omp section +30 print *, "Error in opening file" +!$omp end sections +10 print *, 'Jump from section' + +!$omp sections + !$omp section +40 print *, 'Error in opening file' +!$omp end sections +end program OmpConstructSections01 + +function returnFromSections() + !$omp sections + !$omp section + !ERROR: RETURN statement is not allowed in a SECTIONS construct + RETURN + !$omp end sections +end function + +subroutine calledFromWithinSection() + print *, "I am called from within a 'section' structured block" + return +end subroutine calledFromWithinSection + +subroutine continueWithinSections() + integer i + do i = 1, 10 + print *, "Statement within loop but outside section construct" + !$omp sections + !$omp section + IF (i .EQ. 5) THEN + !ERROR: CYCLE to construct outside of SECTIONS construct is not allowed + CYCLE + END IF + !$omp end sections + print *, "Statement within loop but outside section contruct" + end do + + !$omp sections + !$omp section + do i = 1, 10 + CYCLE + end do + !$omp end sections + + !$omp sections + !$omp section + loop_1: do i = 1, 10 + IF (i .EQ. 5) THEN + CYCLE loop_1 + END IF + end do loop_1 + !$omp end sections + + loop_2: do i = 1, 10 + !$omp sections + !$omp section + IF (i .EQ. 5) THEN + !ERROR: CYCLE to construct 'loop_2' outside of SECTIONS construct is not allowed + CYCLE loop_2 + END IF + !$omp end sections + end do loop_2 +end subroutine continueWithinSections + +subroutine breakWithinSections() + loop_3: do i = 1, 10 + !$omp sections + !$omp section + IF (i .EQ. 5) THEN + !ERROR: EXIT to construct 'loop_3' outside of SECTIONS construct is not allowed + EXIT loop_3 + END IF + !$omp end sections + end do loop_3 + + loop_4: do i = 1, 10 + !$omp sections + !$omp section + IF (i .EQ. 5) THEN + !ERROR: EXIT to construct outside of SECTIONS construct is not allowed + EXIT + END IF + !$omp end sections + end do loop_4 + + !$omp sections + !$omp section + do i = 1, 10 + IF (i .EQ. 5) THEN + EXIT + END IF + end do + !$omp end sections + + !$omp sections + !$omp section + loop_5: do i = 1, 10 + IF (i .EQ. 5) THEN + EXIT loop_5 + END IF + end do loop_5 + !$omp end sections +end subroutine breakWithinSections diff --git a/flang/test/Semantics/omp-sections03.f90 b/flang/test/Semantics/omp-sections03.f90 new file mode 100644 index 000000000000..35c17118fe89 --- /dev/null +++ b/flang/test/Semantics/omp-sections03.f90 @@ -0,0 +1,27 @@ +! RUN: %python %S/test_errors.py %s %flang -fopenmp +!XFAIL: * +! OpenMP version 5.0.0 +! 2.8.1 sections construct +! Orphaned section directives are prohibited. That is, the section directives must appear within the sections construct and must not be encountered elsewhere in the sections region +!TODO: Error in parsing. Make parser errors more informative. Until then, the test is XFAIL + +program OmpOrphanedSections + use omp_lib + integer counter + counter = 0 + !CHECK: expected 'END' + !CHECK: END PROGRAM statement + !CHECK: in the context: main program + !CHECK: expected 'END PROGRAM' + !CHECK: in the context: END PROGRAM statement + !CHECK: in the context: main program + !$omp section + print *, "An orphaned section containing a single statement" + !$omp section + counter = counter + 1 + print *, "An orphaned section containing multiple statements" +!$omp sections + !$omp section + print *, "Not an orphan structured block" +!$omp end sections +end program OmpOrphanedSections diff --git a/flang/test/Semantics/omp-simd01.f90 b/flang/test/Semantics/omp-simd01.f90 index fb86fbaf5675..4fa166b1d4b3 100644 --- a/flang/test/Semantics/omp-simd01.f90 +++ b/flang/test/Semantics/omp-simd01.f90 @@ -1,22 +1,40 @@ -! RUN: not %flang -fsyntax-only -fopenmp %s 2>&1 | FileCheck %s -! OpenMP Version 4.5 -! 2.8.1 simd Construct -! A program that branches into or out of a simd region is non-conforming. +! RUN: %python %S/test_errors.py %s %flang -fopenmp +! OpenMP Version 5.0 +! 2.9.3.1 simd Construct +! - A program that branches into or out of a simd region is non-conforming. +! - The associated loops must be structured blocks program omp_simd - integer i, j + integer i, j - !$omp simd - do i = 1, 10 - do j = 1, 10 - print *, "omp simd" - !CHECK: invalid branch leaving an OpenMP structured block - goto 10 - end do - end do - !$omp end simd - - !CHECK: Outside the enclosing SIMD directive - 10 stop + !$omp simd + do i = 1, 10 + do j = 1, 10 + print *, "omp simd" + !ERROR: invalid branch leaving an OpenMP structured block + goto 10 + end do + if (i .EQ. 5) THEN + call function1() + else if (i .EQ. 7) THEN + open (10, file="random-file-name.txt", err=20) +20 print *, "Error message doesn't branch out of the loop's structured block" + else + !ERROR: invalid branch leaving an OpenMP structured block + open (10, file="random-file-name.txt", err=10) + end if + end do + !$omp end simd +10 stop end program omp_simd + +subroutine function1() + integer i, option + option = 1 + !$omp simd + do i = 1, 10 + print *, "CORRECT SIMD LOOP" + end do + !$omp end simd +end subroutine function1