[OPENMP 4.5] Parsing/sema analysis for 'depend(source)' clause in 'ordered' directive.

OpenMP 4.5 adds 'depend(source)' clause for 'ordered' directive to support cross-iteration dependence. Patch adds parsing and semantic analysis for this construct.

llvm-svn: 255986
This commit is contained in:
Alexey Bataev 2015-12-18 05:05:56 +00:00
parent 125592dc8d
commit eb48235033
13 changed files with 178 additions and 41 deletions

View File

@ -213,5 +213,5 @@ def err_arcmt_nsinvocation_ownership : Error<"NSInvocation's %0 is not safe to b
// OpenMP
def err_omp_more_one_clause : Error<
"directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier}2">;
"directive '#pragma omp %0' cannot contain more than one '%1' clause%select{| with '%3' name modifier| with 'source' dependence}2">;
}

View File

@ -916,6 +916,8 @@ def warn_pragma_omp_ignored : Warning<
def warn_omp_extra_tokens_at_eol : Warning<
"extra tokens at the end of '#pragma omp %0' are ignored">,
InGroup<ExtraTokens>;
def warn_pragma_expected_colon_r_paren : Warning<
"missing ':' or ')' after %0 - ignoring">, InGroup<IgnoredPragmas>;
def err_omp_unknown_directive : Error<
"expected an OpenMP directive">;
def err_omp_unexpected_directive : Error<
@ -925,7 +927,7 @@ def err_omp_expected_punc : Error<
def err_omp_unexpected_clause : Error<
"unexpected OpenMP clause '%0' in directive '#pragma omp %1'">;
def err_omp_immediate_directive : Error<
"'#pragma omp %0' cannot be an immediate substatement">;
"'#pragma omp %0' %select{|with '%2' clause }1cannot be an immediate substatement">;
def err_omp_expected_identifier_for_critical : Error<
"expected identifier specifying the name of the 'omp critical' directive">;
def err_omp_unknown_map_type : Error<

View File

@ -7911,6 +7911,8 @@ def note_omp_previous_named_if_clause : Note<
"previous clause with directive name modifier specified here">;
def err_omp_ordered_directive_with_param : Error<
"'ordered' directive %select{without any clauses|with 'threads' clause}0 cannot be closely nested inside ordered region with specified parameter">;
def err_omp_ordered_directive_without_param : Error<
"'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter">;
def note_omp_ordered_param : Note<
"'ordered' clause with specified parameter">;
def err_omp_expected_base_var_name : Error<
@ -7947,6 +7949,8 @@ def err_omp_firstprivate_and_lastprivate_in_distribute : Error<
"lastprivate variable cannot be firstprivate in '#pragma omp distribute'">;
def err_omp_firstprivate_distribute_in_teams_reduction : Error<
"reduction variable in '#pragma omp teams' cannot be firstprivate in '#pragma omp distribute'">;
def err_omp_depend_clause_thread_simd : Error<
"'depend' clauses cannot be mixed with '%0' clause">;
} // end of OpenMP category
let CategoryName = "Related Result Type Issue" in {

View File

@ -254,6 +254,7 @@ OPENMP_SCHEDULE_KIND(runtime)
OPENMP_DEPEND_KIND(in)
OPENMP_DEPEND_KIND(out)
OPENMP_DEPEND_KIND(inout)
OPENMP_DEPEND_KIND(source)
// Modifiers for 'linear' clause.
OPENMP_LINEAR_KIND(val)
@ -351,6 +352,7 @@ OPENMP_TEAMS_CLAUSE(thread_limit)
// TODO More clauses for 'ordered' directive.
OPENMP_ORDERED_CLAUSE(threads)
OPENMP_ORDERED_CLAUSE(simd)
OPENMP_ORDERED_CLAUSE(depend)
// Map types and map type modifier for 'map' clause.
OPENMP_MAP_KIND(alloc)

View File

@ -2478,7 +2478,9 @@ private:
///
/// \param Kind Kind of current clause.
///
OMPClause *ParseOpenMPVarListClause(OpenMPClauseKind Kind);
OMPClause *ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind Kind);
public:
bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
bool AllowDestructorName,

View File

@ -873,14 +873,14 @@ void OMPClausePrinter::VisitOMPFlushClause(OMPFlushClause *Node) {
}
void OMPClausePrinter::VisitOMPDependClause(OMPDependClause *Node) {
OS << "depend(";
OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
Node->getDependencyKind());
if (!Node->varlist_empty()) {
OS << "depend(";
OS << getOpenMPSimpleClauseTypeName(Node->getClauseKind(),
Node->getDependencyKind())
<< " :";
OS << " :";
VisitOMPClauseList(Node, ' ');
OS << ")";
}
OS << ")";
}
void OMPClausePrinter::VisitOMPMapClause(OMPMapClause *Node) {

View File

@ -2519,6 +2519,7 @@ void CGOpenMPRuntime::emitTaskCall(
case OMPC_DEPEND_inout:
DepKind = DepInOut;
break;
case OMPC_DEPEND_source:
case OMPC_DEPEND_unknown:
llvm_unreachable("Unknown task dependence type");
}

View File

@ -215,7 +215,7 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
case OMPD_cancel:
if (!StandAloneAllowed) {
Diag(Tok, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind);
<< getOpenMPDirectiveName(DKind) << 0;
}
HasAssociatedStatement = false;
// Fall through for further analysis.
@ -295,6 +295,18 @@ Parser::ParseOpenMPDeclarativeOrExecutableDirective(bool StandAloneAllowed) {
// Consume final annot_pragma_openmp_end.
ConsumeToken();
// OpenMP [2.13.8, ordered Construct, Syntax]
// If the depend clause is specified, the ordered construct is a stand-alone
// directive.
if (DKind == OMPD_ordered && FirstClauses[OMPC_depend].getInt()) {
if (!StandAloneAllowed) {
Diag(Loc, diag::err_omp_immediate_directive)
<< getOpenMPDirectiveName(DKind) << 1
<< getOpenMPClauseName(OMPC_depend);
}
HasAssociatedStatement = false;
}
StmtResult AssociatedStmt;
if (HasAssociatedStatement) {
// The body is a block scope like in Lambdas and Blocks.
@ -524,7 +536,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_flush:
case OMPC_depend:
case OMPC_map:
Clause = ParseOpenMPVarListClause(CKind);
Clause = ParseOpenMPVarListClause(DKind, CKind);
break;
case OMPC_unknown:
Diag(Tok, diag::warn_omp_extra_tokens_at_eol)
@ -793,7 +805,7 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
/// flush-clause:
/// 'flush' '(' list ')'
/// depend-clause:
/// 'depend' '(' in | out | inout : list ')'
/// 'depend' '(' in | out | inout : list | source ')'
/// map-clause:
/// 'map' '(' [ [ always , ]
/// to | from | tofrom | alloc | release | delete ':' ] list ')';
@ -802,7 +814,8 @@ static bool ParseReductionId(Parser &P, CXXScopeSpec &ReductionIdScopeSpec,
/// list
/// modifier(list)
/// where modifier is 'val' (C) or 'ref', 'val' or 'uval'(C++).
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
OMPClause *Parser::ParseOpenMPVarListClause(OpenMPDirectiveKind DKind,
OpenMPClauseKind Kind) {
SourceLocation Loc = Tok.getLocation();
SourceLocation LOpen = ConsumeToken();
SourceLocation ColonLoc = SourceLocation();
@ -858,11 +871,23 @@ OMPClause *Parser::ParseOpenMPVarListClause(OpenMPClauseKind Kind) {
StopBeforeMatch);
} else {
ConsumeToken();
// Special processing for depend(source) clause.
if (DKind == OMPD_ordered && DepKind == OMPC_DEPEND_source) {
// Parse ')'.
T.consumeClose();
return Actions.ActOnOpenMPVarListClause(
Kind, llvm::None, /*TailExpr=*/nullptr, Loc, LOpen,
/*ColonLoc=*/SourceLocation(), Tok.getLocation(),
ReductionIdScopeSpec, DeclarationNameInfo(), DepKind,
LinearModifier, MapTypeModifier, MapType, DepLinMapLoc);
}
}
if (Tok.is(tok::colon)) {
ColonLoc = ConsumeToken();
} else {
Diag(Tok, diag::warn_pragma_expected_colon) << "dependency type";
Diag(Tok, DKind == OMPD_ordered ? diag::warn_pragma_expected_colon_r_paren
: diag::warn_pragma_expected_colon)
<< "dependency type";
}
} else if (Kind == OMPC_linear) {
// Try to parse modifier if any.

View File

@ -4574,36 +4574,59 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
getCurFunction()->setHasBranchProtectedScope();
OMPClause *DependFound = nullptr;
OMPClause *DependSourceClause = nullptr;
bool ErrorFound = false;
OMPThreadsClause *TC = nullptr;
OMPSIMDClause *SC = nullptr;
for (auto *C: Clauses) {
if (C->getClauseKind() == OMPC_threads)
for (auto *C : Clauses) {
if (auto *DC = dyn_cast<OMPDependClause>(C)) {
DependFound = C;
if (DC->getDependencyKind() == OMPC_DEPEND_source) {
if (DependSourceClause) {
Diag(C->getLocStart(), diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(OMPD_ordered)
<< getOpenMPClauseName(OMPC_depend) << 2;
ErrorFound = true;
} else
DependSourceClause = C;
}
} else 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
// is specified.
if (auto *Param = DSAStack->getParentOrderedRegionParam()) {
SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr);
Diag(Param->getLocStart(), diag::note_omp_ordered_param);
return StmtError();
}
if (!SC && isOpenMPSimdDirective(DSAStack->getParentDirective())) {
if (!ErrorFound && !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);
ErrorFound = true;
} else if (DependFound && (TC || SC)) {
Diag(DependFound->getLocStart(), diag::err_omp_depend_clause_thread_simd)
<< getOpenMPClauseName(TC ? TC->getClauseKind() : SC->getClauseKind());
ErrorFound = true;
} else if (DependFound && !DSAStack->getParentOrderedRegionParam()) {
Diag(DependFound->getLocStart(),
diag::err_omp_ordered_directive_without_param);
ErrorFound = true;
} else if (TC || Clauses.empty()) {
if (auto *Param = DSAStack->getParentOrderedRegionParam()) {
SourceLocation ErrLoc = TC ? TC->getLocStart() : StartLoc;
Diag(ErrLoc, diag::err_omp_ordered_directive_with_param)
<< (TC != nullptr);
Diag(Param->getLocStart(), diag::note_omp_ordered_param);
ErrorFound = true;
}
}
if ((!AStmt && !DependFound) || ErrorFound)
return StmtError();
if (AStmt) {
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
getCurFunction()->setHasBranchProtectedScope();
}
return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
@ -7966,18 +7989,30 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
SourceLocation DepLoc, SourceLocation ColonLoc,
ArrayRef<Expr *> VarList, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc) {
if (DepKind == OMPC_DEPEND_unknown) {
if (DSAStack->getCurrentDirective() == OMPD_ordered &&
DepKind != OMPC_DEPEND_source) {
std::string Values = "'";
Values += getOpenMPSimpleClauseTypeName(OMPC_depend, OMPC_DEPEND_source);
Values += "'";
Diag(DepLoc, diag::err_omp_unexpected_clause_value)
<< Values << getOpenMPClauseName(OMPC_depend);
return nullptr;
}
if (DSAStack->getCurrentDirective() != OMPD_ordered &&
(DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source)) {
std::string Values;
std::string Sep(", ");
for (unsigned i = 0; i < OMPC_DEPEND_unknown; ++i) {
if (i == OMPC_DEPEND_source)
continue;
Values += "'";
Values += getOpenMPSimpleClauseTypeName(OMPC_depend, i);
Values += "'";
switch (i) {
case OMPC_DEPEND_unknown - 2:
case OMPC_DEPEND_unknown - 3:
Values += " or ";
break;
case OMPC_DEPEND_unknown - 1:
case OMPC_DEPEND_unknown - 2:
break;
default:
Values += Sep;
@ -8018,7 +8053,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
Vars.push_back(RefExpr->IgnoreParenImpCasts());
}
if (Vars.empty())
if (DepKind != OMPC_DEPEND_source && Vars.empty())
return nullptr;
return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind,

View File

@ -7071,10 +7071,7 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
}
}
StmtResult AssociatedStmt;
if (D->hasAssociatedStmt()) {
if (!D->getAssociatedStmt()) {
return StmtError();
}
if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
getDerived().getSema().ActOnOpenMPRegionStart(D->getDirectiveKind(),
/*CurScope=*/nullptr);
StmtResult Body;

View File

@ -42,6 +42,11 @@ T tmain (T argc) {
{
a=2;
}
#pragma omp parallel for ordered(1)
for (int i =0 ; i < argc; ++i) {
#pragma omp ordered depend(source)
a = 2;
}
return (0);
}
@ -76,7 +81,11 @@ T tmain (T argc) {
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for ordered(1)
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
// CHECK-NEXT: #pragma omp ordered depend(source)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK: static T a;
// CHECK-NEXT: #pragma omp for ordered
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
@ -108,7 +117,13 @@ T tmain (T argc) {
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for ordered(1)
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
// CHECK-NEXT: #pragma omp ordered depend(source)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-LABEL: int main(
int main (int argc, char **argv) {
int b = argc, c, d, e, f, g;
static int a;
@ -143,6 +158,11 @@ int main (int argc, char **argv) {
{
a=2;
}
#pragma omp parallel for ordered(1)
for (int i =0 ; i < argc; ++i) {
#pragma omp ordered depend(source)
a = 2;
}
// CHECK-NEXT: #pragma omp for ordered
// CHECK-NEXT: for (int i = 0; i < argc; ++i)
// CHECK-NEXT: #pragma omp ordered
@ -172,6 +192,11 @@ int main (int argc, char **argv) {
// CHECK-NEXT: #pragma omp ordered simd
// CHECK-NEXT: {
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
// CHECK-NEXT: #pragma omp parallel for ordered(1)
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
// CHECK-NEXT: #pragma omp ordered depend(source)
// CHECK-NEXT: a = 2;
// CHECK-NEXT: }
return tmain(argc);
}

View File

@ -90,6 +90,27 @@ T foo() {
{
foo();
}
#pragma omp ordered depend(source) // expected-error {{OpenMP constructs may not be nested inside a simd region}}
}
#pragma omp parallel for ordered
for (int i = 0; i < 10; ++i) {
#pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
}
#pragma omp parallel for ordered(1) // expected-note 3 {{'ordered' clause with specified parameter}}
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp ordered depend(source)
if (i == j)
#pragma omp ordered depend(source) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
;
#pragma omp ordered depend(source) threads // expected-error {{'depend' clauses cannot be mixed with 'threads' clause}}
#pragma omp ordered simd depend(source) // expected-error {{'depend' clauses cannot be mixed with 'simd' clause}}
#pragma omp ordered depend(source) depend(source) // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'depend' clause with 'source' dependence}}
#pragma omp ordered depend(in : i) // expected-error {{expected 'source' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
}
}
return T();
@ -182,6 +203,27 @@ int foo() {
{
foo();
}
#pragma omp ordered depend(source) // expected-error {{OpenMP constructs may not be nested inside a simd region}}
}
#pragma omp parallel for ordered
for (int i = 0; i < 10; ++i) {
#pragma omp ordered depend(source) // expected-error {{'ordered' directive with 'depend' clause cannot be closely nested inside ordered region without specified parameter}}
}
#pragma omp parallel for ordered(1) // expected-note 3 {{'ordered' clause with specified parameter}}
for (int i = 0; i < 10; ++i) {
for (int j = 0; j < 10; ++j) {
#pragma omp ordered depend // expected-error {{expected '(' after 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
#pragma omp ordered depend( // expected-error {{expected ')'}} expected-error {{expected 'source' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}} expected-warning {{missing ':' or ')' after dependency type - ignoring}} expected-note {{to match this '('}}
#pragma omp ordered depend(source // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp ordered depend(source)
if (i == j)
#pragma omp ordered depend(source) // expected-error {{'#pragma omp ordered' with 'depend' clause cannot be an immediate substatement}}
;
#pragma omp ordered depend(source) threads // expected-error {{'depend' clauses cannot be mixed with 'threads' clause}}
#pragma omp ordered simd depend(source) // expected-error {{'depend' clauses cannot be mixed with 'simd' clause}}
#pragma omp ordered depend(source) depend(source) // expected-error {{directive '#pragma omp ordered' cannot contain more than one 'depend' clause with 'source' dependence}}
#pragma omp ordered depend(in : i) // expected-error {{expected 'source' in OpenMP clause 'depend'}} expected-error {{'ordered' directive without any clauses cannot be closely nested inside ordered region with specified parameter}}
}
}
return foo<int>();

View File

@ -24,6 +24,8 @@ int main(int argc, char **argv, char *env[]) {
#pragma omp task depend ( // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-error {{expected ')'}} expected-note {{to match this '('}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend () // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend (argc // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp task depend (source : argc) // expected-error {{expected 'in', 'out' or 'inout' in OpenMP clause 'depend'}}
#pragma omp task depend (source) // expected-error {{expected expression}} expected-warning {{missing ':' after dependency type - ignoring}}
#pragma omp task depend (in : argc)) // expected-warning {{extra tokens at the end of '#pragma omp task' are ignored}}
#pragma omp task depend (out: ) // expected-error {{expected expression}}
#pragma omp task depend (inout : foobool(argc)), depend (in, argc) // expected-error {{expected variable name, array element or array section}} expected-warning {{missing ':' after dependency type - ignoring}} expected-error {{expected expression}}