[OPENMP 4.1] Add 'simd' clause for 'ordered' directive.

Parsing and sema analysis for 'simd' clause in 'ordered' directive.
Description
If the simd clause is specified, the ordered regions encountered by any thread will use only a single SIMD lane to execute the ordered
regions in the order of the loop iterations.
Restrictions
An ordered construct with the simd clause is the only OpenMP construct that can appear in the simd region

llvm-svn: 248696
This commit is contained in:
Alexey Bataev 2015-09-28 06:39:35 +00:00
parent f32f5f2305
commit d14d1e6f25
17 changed files with 289 additions and 7 deletions

View File

@ -2539,6 +2539,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) {
return true;
}
template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {

View File

@ -2561,6 +2561,36 @@ public:
}
};
/// \brief This represents 'simd' clause in the '#pragma omp ...' directive.
///
/// \code
/// #pragma omp ordered simd
/// \endcode
/// In this example directive '#pragma omp ordered' has simple 'simd' clause.
///
class OMPSIMDClause : public OMPClause {
public:
/// \brief Build 'simd' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
///
OMPSIMDClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPClause(OMPC_simd, StartLoc, EndLoc) {}
/// \brief Build an empty clause.
///
OMPSIMDClause() : OMPClause(OMPC_simd, SourceLocation(), SourceLocation()) {}
static bool classof(const OMPClause *T) {
return T->getClauseKind() == OMPC_simd;
}
child_range children() {
return child_range(child_iterator(), child_iterator());
}
};
} // end namespace clang
#endif

View File

@ -2571,6 +2571,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPThreadsClause(OMPThreadsClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPSIMDClause(OMPSIMDClause *) {
return true;
}
template <typename Derived>
template <typename T>
bool RecursiveASTVisitor<Derived>::VisitOMPClauseList(T *Node) {

View File

@ -145,6 +145,7 @@ OPENMP_CLAUSE(seq_cst, OMPSeqCstClause)
OPENMP_CLAUSE(depend, OMPDependClause)
OPENMP_CLAUSE(device, OMPDeviceClause)
OPENMP_CLAUSE(threads, OMPThreadsClause)
OPENMP_CLAUSE(simd, OMPSIMDClause)
// Clauses allowed for OpenMP directive 'parallel'.
OPENMP_PARALLEL_CLAUSE(if)
@ -318,6 +319,7 @@ OPENMP_TEAMS_CLAUSE(reduction)
// Clauses allowed for OpenMP directive 'ordered'.
// TODO More clauses for 'ordered' directive.
OPENMP_ORDERED_CLAUSE(threads)
OPENMP_ORDERED_CLAUSE(simd)
#undef OPENMP_LINEAR_KIND
#undef OPENMP_DEPEND_KIND

View File

@ -7997,7 +7997,10 @@ public:
SourceLocation EndLoc);
/// \brief Called on well-formed 'threads' clause.
OMPClause *ActOnOpenMPThreadsClause(SourceLocation StartLoc,
SourceLocation EndLoc);
SourceLocation EndLoc);
/// \brief Called on well-formed 'simd' clause.
OMPClause *ActOnOpenMPSIMDClause(SourceLocation StartLoc,
SourceLocation EndLoc);
OMPClause *ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> Vars, Expr *TailExpr,

View File

@ -701,6 +701,8 @@ void OMPClausePrinter::VisitOMPThreadsClause(OMPThreadsClause *) {
OS << "threads";
}
void OMPClausePrinter::VisitOMPSIMDClause(OMPSIMDClause *) { OS << "simd"; }
void OMPClausePrinter::VisitOMPDeviceClause(OMPDeviceClause *Node) {
OS << "device(";
Node->getDevice()->printPretty(OS, nullptr, Policy, 0);

View File

@ -335,6 +335,8 @@ void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseProfiler::VisitOMPThreadsClause(const OMPThreadsClause *) {}
void OMPClauseProfiler::VisitOMPSIMDClause(const OMPSIMDClause *) {}
template<typename T>
void OMPClauseProfiler::VisitOMPClauseList(T *Node) {
for (auto *E : Node->varlists()) {

View File

@ -129,6 +129,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
case OMPC_seq_cst:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");
@ -214,6 +215,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_seq_cst:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
break;
}
llvm_unreachable("Invalid OpenMP simple clause kind");

View File

@ -2210,6 +2210,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
case OMPC_mergeable:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
llvm_unreachable("Clause is not allowed in 'omp atomic'.");
}
}

View File

@ -394,7 +394,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind,
/// schedule-clause | copyin-clause | copyprivate-clause | untied-clause |
/// mergeable-clause | flush-clause | read-clause | write-clause |
/// update-clause | capture-clause | seq_cst-clause | device-clause |
/// simdlen-clause | threads-clause
/// simdlen-clause | threads-clause | simd-clause
///
OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind CKind, bool FirstClause) {
@ -473,6 +473,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_capture:
case OMPC_seq_cst:
case OMPC_threads:
case OMPC_simd:
// OpenMP [2.7.1, Restrictions, p. 9]
// Only one ordered clause can appear on a loop directive.
// OpenMP [2.7.1, Restrictions, C/C++, p. 4]
@ -605,6 +606,9 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) {
/// threads-clause:
/// 'threads'
///
/// simd-clause:
/// 'simd'
///
OMPClause *Parser::ParseOpenMPClause(OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
ConsumeAnyToken();

View File

@ -1547,7 +1547,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | simd | taskwait | |
// | simd | taskgroup | |
// | simd | flush | |
// | simd | ordered | |
// | simd | ordered | + (with simd clause) |
// | simd | atomic | |
// | simd | target | |
// | simd | teams | |
@ -1573,7 +1573,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | for simd | taskwait | |
// | for simd | taskgroup | |
// | for simd | flush | |
// | for simd | ordered | |
// | for simd | ordered | + (with simd clause) |
// | for simd | atomic | |
// | for simd | target | |
// | for simd | teams | |
@ -1599,7 +1599,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel for simd| taskwait | |
// | parallel for simd| taskgroup | |
// | parallel for simd| flush | |
// | parallel for simd| ordered | |
// | parallel for simd| ordered | + (with simd clause) |
// | parallel for simd| atomic | |
// | parallel for simd| target | |
// | parallel for simd| teams | |
@ -1877,9 +1877,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
ShouldBeInOrderedRegion,
ShouldBeInTargetRegion
} Recommend = NoRecommend;
if (isOpenMPSimdDirective(ParentRegion)) {
if (isOpenMPSimdDirective(ParentRegion) && CurrentRegion != OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd);
return true;
}
@ -1987,9 +1990,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// atomic, or explicit task region.
// An ordered region must be closely nested inside a loop region (or
// parallel loop region) with an ordered clause.
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
NestingProhibited = ParentRegion == OMPD_critical ||
ParentRegion == OMPD_task ||
!Stack->isParentOrderedRegion();
!(isOpenMPSimdDirective(ParentRegion) ||
Stack->isParentOrderedRegion());
Recommend = ShouldBeInOrderedRegion;
} else if (isOpenMPTeamsDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
@ -4146,9 +4153,12 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
getCurFunction()->setHasBranchProtectedScope();
OMPThreadsClause *TC = nullptr;
OMPSIMDClause *SC = nullptr;
for (auto *C: Clauses) {
if (C->getClauseKind() == OMPC_threads)
TC = cast<OMPThreadsClause>(C);
else if (C->getClauseKind() == OMPC_simd)
SC = cast<OMPSIMDClause>(C);
}
// TODO: this must happen only if 'threads' clause specified or if no clauses
@ -4159,6 +4169,13 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Diag(Param->getLocStart(), diag::note_omp_ordered_param);
return StmtError();
}
if (!SC && isOpenMPSimdDirective(DSAStack->getParentDirective())) {
// OpenMP [2.8.1,simd Construct, Restrictions]
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
Diag(StartLoc, diag::err_omp_prohibited_region_simd);
return StmtError();
}
return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
@ -5009,6 +5026,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_seq_cst:
case OMPC_depend:
case OMPC_threads:
case OMPC_simd:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@ -5270,6 +5288,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@ -5398,6 +5417,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_depend:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}
@ -5504,6 +5524,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_threads:
Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc);
break;
case OMPC_simd:
Res = ActOnOpenMPSIMDClause(StartLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
case OMPC_num_threads:
@ -5578,6 +5601,11 @@ OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc,
return new (Context) OMPThreadsClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPSIMDClause(SourceLocation StartLoc,
SourceLocation EndLoc) {
return new (Context) OMPSIMDClause(StartLoc, EndLoc);
}
OMPClause *Sema::ActOnOpenMPVarListClause(
OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr,
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
@ -5644,6 +5672,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_seq_cst:
case OMPC_device:
case OMPC_threads:
case OMPC_simd:
case OMPC_unknown:
llvm_unreachable("Clause is not allowed.");
}

View File

@ -7372,6 +7372,12 @@ TreeTransform<Derived>::TransformOMPThreadsClause(OMPThreadsClause *C) {
return C;
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPSIMDClause(OMPSIMDClause *C) {
// No need to rebuild this clause, no template-dependent parameters.
return C;
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) {

View File

@ -1780,6 +1780,9 @@ OMPClause *OMPClauseReader::readClause() {
case OMPC_threads:
C = new (Context) OMPThreadsClause();
break;
case OMPC_simd:
C = new (Context) OMPSIMDClause();
break;
case OMPC_private:
C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]);
break;
@ -1904,6 +1907,8 @@ void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseReader::VisitOMPThreadsClause(OMPThreadsClause *) {}
void OMPClauseReader::VisitOMPSIMDClause(OMPSIMDClause *) {}
void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
unsigned NumVars = C->varlist_size();

View File

@ -1812,6 +1812,8 @@ void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseWriter::VisitOMPThreadsClause(OMPThreadsClause *) {}
void OMPClauseWriter::VisitOMPSIMDClause(OMPSIMDClause *) {}
void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) {
Record.push_back(C->varlist_size());
Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record);

View File

@ -24,6 +24,24 @@ T tmain (T argc) {
{
a=2;
}
#pragma omp simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
#pragma omp for simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
#pragma omp parallel for simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
return (0);
}
@ -40,6 +58,24 @@ T tmain (T argc) {
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK: static T a;
// CHECK-NEXT: #pragma omp for ordered
@ -54,6 +90,24 @@ T tmain (T argc) {
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
@ -71,6 +125,24 @@ int main (int argc, char **argv) {
{
a=2;
}
#pragma omp simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
#pragma omp for simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
#pragma omp parallel for simd
for (int i =0 ; i < argc; ++i)
#pragma omp ordered simd
{
a=2;
}
// CHECK-NEXT: #pragma omp for ordered
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered
@ -82,6 +154,24 @@ int main (int argc, char **argv) {
// CHECK-NEXT: #pragma omp ordered threads
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for simd
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
return tmain(argc);
}

View File

@ -45,6 +45,52 @@ T foo() {
foo();
}
}
#pragma omp ordered simd simd // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'simd' clause}}
{
foo();
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp parallel for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp parallel for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
return T();
}
@ -91,6 +137,52 @@ int foo() {
foo();
}
}
#pragma omp ordered simd simd // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'simd' clause}}
{
foo();
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp parallel for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
#pragma omp parallel for simd
for (int i = 0; i < 10; ++i) {
#pragma omp ordered threads // expected-error {{OpenMP constructs may not be nested inside a simd region}}
{
foo();
}
}
return foo<int>();
}

View File

@ -2068,6 +2068,8 @@ void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseEnqueue::VisitOMPThreadsClause(const OMPThreadsClause *) {}
void OMPClauseEnqueue::VisitOMPSIMDClause(const OMPSIMDClause *) {}
void OMPClauseEnqueue::VisitOMPDeviceClause(const OMPDeviceClause *C) {
Visitor->AddStmt(C->getDevice());
}