[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
This commit is contained in:
Nimish Mishra 2021-10-01 00:41:57 +05:30 committed by nimishra
parent 237e9059f7
commit 063c5bc31b
4 changed files with 241 additions and 19 deletions

View File

@ -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 <typename T> bool Pre(const T &) { return true; }
template <typename T> 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

View File

@ -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

View File

@ -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

View File

@ -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