diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 31530444d6920..fcfe8a3fffeae 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1368,6 +1368,12 @@ def err_acc_invalid_default_clause_kind : Error<"invalid value for 'default' clause; expected 'present' or 'none'">; def err_acc_invalid_tag_kind : Error<"invalid tag %0 on '%1' %select{directive|clause}2">; +def err_acc_expected_reduction_operator + : Error<"missing reduction operator, expected '+', '*', 'max', 'min', '&', " + "'|', '^', '&&', or '||', follwed by a ':'">; +def err_acc_invalid_reduction_operator + : Error<"invalid reduction operator, expected '+', '*', 'max', 'min', " + "'&', '|', '^', '&&', or '||'">; // OpenMP support. def warn_pragma_omp_ignored : Warning< diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h index 87da3fc108ce0..23d41c41b9a63 100644 --- a/clang/include/clang/Basic/OpenACCKinds.h +++ b/clang/include/clang/Basic/OpenACCKinds.h @@ -214,6 +214,9 @@ enum class OpenACCClauseKind { /// 'copyin' clause, allowed on Compute and Combined constructs, plus 'data', /// 'enter data', and 'declare'. Create, + /// 'reduction' clause, allowed on Parallel, Serial, Loop, and the combined + /// constructs. + Reduction, /// Represents an invalid clause, for the purposes of parsing. Invalid, @@ -306,6 +309,9 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out, case OpenACCClauseKind::Create: return Out << "create"; + case OpenACCClauseKind::Reduction: + return Out << "reduction"; + case OpenACCClauseKind::Invalid: return Out << ""; } @@ -319,6 +325,29 @@ enum class OpenACCDefaultClauseKind { /// Not a valid option. Invalid, }; + +enum class OpenACCReductionOperator { + /// '+'. + Addition, + /// '*'. + Multiplication, + /// 'max'. + Max, + /// 'min'. + Min, + /// '&'. + BitwiseAnd, + /// '|'. + BitwiseOr, + /// '^'. + BitwiseXOr, + /// '&&'. + And, + /// '||'. + Or, + /// Invalid Reduction Clause Kind. + Invalid, +}; } // namespace clang #endif // LLVM_CLANG_BASIC_OPENACCKINDS_H diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp index 5196eb9056be2..b397553de01a0 100644 --- a/clang/lib/Parse/ParseOpenACC.cpp +++ b/clang/lib/Parse/ParseOpenACC.cpp @@ -112,6 +112,7 @@ OpenACCClauseKind getOpenACCClauseKind(Token Tok) { .Case("nohost", OpenACCClauseKind::NoHost) .Case("present", OpenACCClauseKind::Present) .Case("private", OpenACCClauseKind::Private) + .Case("reduction", OpenACCClauseKind::Reduction) .Case("self", OpenACCClauseKind::Self) .Case("seq", OpenACCClauseKind::Seq) .Case("use_device", OpenACCClauseKind::UseDevice) @@ -260,6 +261,47 @@ bool isOpenACCDirectiveKind(OpenACCDirectiveKind Kind, Token Tok) { llvm_unreachable("Unknown 'Kind' Passed"); } +OpenACCReductionOperator ParseReductionOperator(Parser &P) { + // If there is no colon, treat as if the reduction operator was missing, else + // we probably will not recover from it in the case where an expression starts + // with one of the operator tokens. + if (P.NextToken().isNot(tok::colon)) { + P.Diag(P.getCurToken(), diag::err_acc_expected_reduction_operator); + return OpenACCReductionOperator::Invalid; + } + Token ReductionKindTok = P.getCurToken(); + // Consume both the kind and the colon. + P.ConsumeToken(); + P.ConsumeToken(); + + switch (ReductionKindTok.getKind()) { + case tok::plus: + return OpenACCReductionOperator::Addition; + case tok::star: + return OpenACCReductionOperator::Multiplication; + case tok::amp: + return OpenACCReductionOperator::BitwiseAnd; + case tok::pipe: + return OpenACCReductionOperator::BitwiseOr; + case tok::caret: + return OpenACCReductionOperator::BitwiseXOr; + case tok::ampamp: + return OpenACCReductionOperator::And; + case tok::pipepipe: + return OpenACCReductionOperator::Or; + case tok::identifier: + if (ReductionKindTok.getIdentifierInfo()->isStr("max")) + return OpenACCReductionOperator::Max; + if (ReductionKindTok.getIdentifierInfo()->isStr("min")) + return OpenACCReductionOperator::Min; + LLVM_FALLTHROUGH; + default: + P.Diag(ReductionKindTok, diag::err_acc_invalid_reduction_operator); + return OpenACCReductionOperator::Invalid; + } + llvm_unreachable("Reduction op token kind not caught by 'default'?"); +} + /// Used for cases where we expect an identifier-like token, but don't want to /// give awkward error messages in cases where it is accidentially a keyword. bool expectIdentifierOrKeyword(Parser &P) { @@ -419,6 +461,7 @@ ClauseParensKind getClauseParensKind(OpenACCDirectiveKind DirKind, case OpenACCClauseKind::Device: case OpenACCClauseKind::Link: case OpenACCClauseKind::Host: + case OpenACCClauseKind::Reduction: return ClauseParensKind::Required; case OpenACCClauseKind::Auto: @@ -581,6 +624,13 @@ bool Parser::ParseOpenACCClauseParams(OpenACCDirectiveKind DirKind, if (ParseOpenACCClauseVarList(Kind)) return true; break; + case OpenACCClauseKind::Reduction: + // If we're missing a clause-kind (or it is invalid), see if we can parse + // the var-list anyway. + ParseReductionOperator(*this); + if (ParseOpenACCClauseVarList(Kind)) + return true; + break; case OpenACCClauseKind::Self: // The 'self' clause is a var-list instead of a 'condition' in the case of // the 'update' clause, so we have to handle it here. U se an assert to diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c index c5638531b68b9..6d548210e816c 100644 --- a/clang/test/ParserOpenACC/parse-clauses.c +++ b/clang/test/ParserOpenACC/parse-clauses.c @@ -619,6 +619,46 @@ void VarListClauses() { // expected-error@+2{{use of undeclared identifier 'invalid'}} // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} #pragma acc serial copyin(invalid s.array[s.value : 5], s.value), seq +} + +void ReductionClauseParsing() { + char *Begin, *End; + // expected-error@+2{{expected '('}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction + // expected-error@+3{{missing reduction operator, expected '+', '*', 'max', 'min', '&', '|', '^', '&&', or '||', follwed by a ':'}} + // expected-error@+2{{expected expression}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction() + // expected-error@+2{{missing reduction operator, expected '+', '*', 'max', 'min', '&', '|', '^', '&&', or '||', follwed by a ':'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(Begin) + // expected-error@+2{{missing reduction operator, expected '+', '*', 'max', 'min', '&', '|', '^', '&&', or '||', follwed by a ':'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(Begin, End) + // expected-error@+2{{missing reduction operator, expected '+', '*', 'max', 'min', '&', '|', '^', '&&', or '||', follwed by a ':'}} + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(+:Begin) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(+:Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(*: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(max : Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(min: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(&: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(|: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(^: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial seq, reduction(&&: Begin, End) + // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}} +#pragma acc serial reduction(||: Begin, End), seq } // expected-warning@+1{{OpenACC directives not yet implemented, pragma ignored}}