ABataev added inline comments. ================ Comment at: include/clang/AST/DeclBase.h:290 @@ -286,3 +289,3 @@ /// IdentifierNamespace - This specifies what IDNS_* namespace this lives in. - unsigned IdentifierNamespace : 12; + unsigned IdentifierNamespace : 13; ---------------- rsmith wrote: > This is not OK; it makes all `Decl`s 4 bytes larger (all the bits of this > 32-bit bitfield were already in use). Can you take a bit out of `DeclKind`? > (Please try to measure the performance impact of that change -- we probably > `DeclKind` in a lot of places, and this will require us to mask off a bit > rather than just performing a byte load.) Done. Tried to measure comp time - did not find any significant changes.
================ Comment at: include/clang/AST/DeclOpenMP.h:99 @@ +98,3 @@ +/// Here 'omp_out += omp_in' is a combiner and 'omp_priv = 0' is an initializer. +class OMPDeclareReductionDecl : public NamedDecl, public DeclContext { +public: ---------------- rsmith wrote: > Why is this a `DeclContext`? Actually declare reduction is very similar to functions. It implicitly declares at least 4 internal variables - omp_in, omp_out, omp_priv and omp_orig. ================ Comment at: include/clang/AST/DeclOpenMP.h:125 @@ +124,3 @@ + : NamedDecl(DK, DC, L, Name), DeclContext(DK), NumReductions(0) { + setModulePrivate(); + } ---------------- rsmith wrote: > Why should a reduction declared at namespace scope not be exported from its > module? Removed. ================ Comment at: include/clang/Basic/DiagnosticSemaKinds.td:7646-7649 @@ -7645,1 +7645,6 @@ "parent region for 'omp %select{cancellation point/cancel}0' construct cannot be ordered">; +def err_omp_reduction_qualified_type : Error<"a type name cannot be qualified with 'const', 'volatile' or 'restrict'">; +def err_omp_reduction_function_type : Error<"a type name cannot be a function type">; +def err_omp_reduction_reference_type : Error<"a type name cannot be a reference type">; +def err_omp_reduction_array_type : Error<"a type name cannot be an array type">; +def err_omp_reduction_redeclared : Error<"previous declaration with type %0 is found">; ---------------- rsmith wrote: > These should say something more specific than "a type name". A type name can > be any of these things; should this say something like "reduction type cannot > be [...]"? Ok, fixed ================ Comment at: lib/CodeGen/CGDecl.cpp:1811 @@ +1810,3 @@ +void CodeGenModule::EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D) { + llvm_unreachable("Codegen for 'omp declare reduction' is not supported yet."); +} ---------------- rsmith wrote: > So, how is code generation for these supposed to work? Do they result in > functions being emitted for the reduction and initialization steps? Are there > name manglings defined for these? Yes, there should be reduction/initialization functions emitted. No, there is no specific manglings for these functions, their names are not specified, so we could define our own rules. ================ Comment at: lib/Parse/ParseOpenMP.cpp:82 @@ +81,3 @@ +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' ---------------- rsmith wrote: > rsmith wrote: > > Please specify what `<reduction_id>` is in this comment. > Can you wrap this a bit better? (Maybe linebreaks and some indentation after > the '(', each ':', and the ')')? Added description from the standard ================ Comment at: lib/Parse/ParseOpenMP.cpp:82-85 @@ +81,6 @@ +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end +/// ---------------- ABataev wrote: > rsmith wrote: > > rsmith wrote: > > > Please specify what `<reduction_id>` is in this comment. > > Can you wrap this a bit better? (Maybe linebreaks and some indentation > > after the '(', each ':', and the ')')? > Added description from the standard Tried to improve it. ================ Comment at: lib/Parse/ParseOpenMP.cpp:84 @@ +83,3 @@ +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end ---------------- rsmith wrote: > This does not match your implementation. Is the initializer required to start > 'omp_priv =' or not? No, not required. Fixed. ================ Comment at: lib/Parse/ParseOpenMP.cpp:99 @@ +98,3 @@ + + DeclarationName Name; + switch (Tok.getKind()) { ---------------- rsmith wrote: > Please factor out a ParseOpenMPReductionId function. Ok, done ================ Comment at: lib/Parse/ParseOpenMP.cpp:102-103 @@ +101,4 @@ + case tok::plus: // '+' + Name = Actions.getASTContext().DeclarationNames.getIdentifier( + &Actions.Context.Idents.get("+")); + ConsumeAnyToken(); ---------------- rsmith wrote: > This is a really strange thing to do. What do these non-identifier names > mean, and when can they be used? Would it make more sense to model these > names as 'operator +' etc, rather than building a "+" identifier? I thought about it, but the problem here is that it will make the code more complex (especially lookup procedure) without any benefits. ================ Comment at: lib/Parse/ParseOpenMP.cpp:252 @@ +251,3 @@ + ExprResult CombinerResult = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + Actions.FinishOpenMPDeclareReductionCombiner(CombinerResult.get()); ---------------- rsmith wrote: > What is the lifetime of temporaries in the reduction expression? Should you > `ActOnFinishFullExpr` here instead? Yes, you're right. Will replace it by ActOnFinishFullExpr. ================ Comment at: lib/Parse/ParseOpenMP.cpp:285-286 @@ +284,4 @@ + // Parse expression. + InitializerResult = + Actions.CorrectDelayedTyposInExpr(ParseAssignmentExpression()); + IsCorrect = !Actions.FinishOpenMPDeclareReductionInitializer( ---------------- rsmith wrote: > Again, is this a full-expression? What is the lifetime of temporaries created > here? Fixed, thanks ================ Comment at: lib/Parse/ParseOpenMP.cpp:412-416 @@ -143,1 +411,7 @@ /// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end +/// ---------------- rsmith wrote: > Seems excessive to list this grammar production three times. Maybe just > > annot_pragma_openmp 'declare' 'reduction' [...] > > here? Ok, done ================ Comment at: lib/Sema/SemaOpenMP.cpp:6589-6597 @@ +6588,11 @@ + ReductionType->isMemberFunctionPointerType()) { + Diag(TyRange.getBegin(), diag::err_omp_reduction_function_type) << TyRange; + return false; + } + if (ReductionType->isReferenceType()) { + Diag(TyRange.getBegin(), diag::err_omp_reduction_reference_type) << TyRange; + return false; + } + if (ReductionType->isArrayType()) { + Diag(TyRange.getBegin(), diag::err_omp_reduction_array_type) << TyRange; + return false; ---------------- rsmith wrote: > Maybe fold these diagnostics into a single one with a parameter to %select > which kind of bad type was provided? Ok, done ================ Comment at: lib/Sema/SemaOpenMP.cpp:6602 @@ +6601,3 @@ + bool IsValid = true; + for (auto &&Data : RegisteredReductionTypes) { + if (Context.hasSameType(ReductionType, Data.first)) { ---------------- rsmith wrote: > Use `auto &` rather than `auto &&` here; you're not binding to a temporary. Fixed ================ Comment at: lib/Sema/SemaOpenMP.cpp:6603-6610 @@ +6602,10 @@ + for (auto &&Data : RegisteredReductionTypes) { + if (Context.hasSameType(ReductionType, Data.first)) { + Diag(TyRange.getBegin(), diag::err_omp_reduction_redeclared) + << ReductionType << TyRange; + Diag(Data.second.getBegin(), diag::note_previous_declaration) + << Data.second; + IsValid = false; + break; + } + } ---------------- rsmith wrote: > What happens if the same type is redeclared in a separate #pragma? It must be diagnosed. And it will be diagnosed later ================ Comment at: lib/Sema/SemaOpenMP.cpp:6644-6657 @@ +6643,16 @@ + + // Create 'T omp_in;' implicit param. + auto *OmpInParm = ImplicitParamDecl::Create( + Context, DRD, Loc, &Context.Idents.get("omp_in"), ReductionType); + // Create 'T &omp_out;' implicit param. + auto *OmpOutParm = ImplicitParamDecl::Create( + Context, DRD, Loc, &Context.Idents.get("omp_out"), + Context.getLValueReferenceType(ReductionType)); + if (S) { + PushOnScopeChains(OmpInParm, S); + PushOnScopeChains(OmpOutParm, S); + } else { + DRD->addDecl(OmpInParm); + DRD->addDecl(OmpOutParm); + } +} ---------------- rsmith wrote: > Given that you only have one `DeclContext` for all the reductions in a > reduction declaration, and each reduction has a different type, how does this > work? Each time we start a reduction for new type I pop pseudo parameters from the scope chains, so the lookup proceadure each time sees only variables with the specific type. But I'll split the construct. ================ Comment at: lib/Sema/SemaOpenMP.cpp:6669-6670 @@ +6668,4 @@ + bool VisitDeclRefExpr(const DeclRefExpr *E) { + if (auto VD = dyn_cast<VarDecl>(E->getDecl())) { + if (!VD->hasLocalStorage()) { + SemaRef.Diag(E->getLocStart(), ---------------- rsmith wrote: > Can you perform this check as you parse, rather than doing it after the fact? Ok, done ================ Comment at: lib/Sema/SemaOpenMP.cpp:6670-6678 @@ +6669,11 @@ + if (auto VD = dyn_cast<VarDecl>(E->getDecl())) { + if (!VD->hasLocalStorage()) { + SemaRef.Diag(E->getLocStart(), + Combiner ? diag::err_omp_wrong_var_for_combiner + : diag::err_omp_wrong_var_for_initializer) + << E->getSourceRange(); + SemaRef.Diag(VD->getLocation(), diag::note_defined_here) + << VD << VD->getSourceRange(); + return true; + } + } ---------------- rsmith wrote: > The check you perform here doesn't match the wording of your diagnostics. > Suppose I write this: > > #pragma omp declare reduction (foo : int : ({ int a = omp_in; a = a * 2; > omp_out += a; })) > > (or a similar example with a lambda-expression or block literal). Is that > valid (as your code suggests) or ill-formed (as the text of your diagnostic > suggests)? > > What happens if the reduction expression indirectly references a global > (through a function call, constructor, overloaded operator, ...)? 1. Yes, this is valid. Because anyway, you're still using only 2 external variables. 'a' is internal. 2. It is unspecified behavior, we have nothing to do with this. ================ Comment at: lib/Sema/SemaOpenMP.cpp:6795-6797 @@ +6794,5 @@ + S = getScopeForContext(DC); + if (S) { + LookupResult Lookup(*this, DRD->getDeclName(), DRD->getLocation(), + LookupOMPReductionName); + Lookup.suppressDiagnostics(); ---------------- rsmith wrote: > This is wrong for template instantiation. It's not possible to perform a > scope-based lookup like this when instantiating a template; the scope > information is already gone. > > If you want this to work, you're going to need to store enough information to > be able to reconstruct the set of reductions declared with the same name in > the same block scope after the fact. (Perhaps you could add a pointer to the > previous reduction with the same name in the same block scope to the Decl?) I know about this problem and thought to solve it later. Thanks for advice, I will try it. ================ Comment at: lib/Sema/SemaTemplateInstantiateDecl.cpp:2487-2489 @@ +2486,5 @@ + /*S=*/nullptr, D->getLocation(), DRD, SubstReductionType); + for (auto *Local : D->noload_decls()) { + auto Lookup = + NewDRD->noload_lookup(cast<NamedDecl>(Local)->getDeclName()); + if (!Lookup.empty()) { ---------------- rsmith wrote: > Don't use `noload_*`. They're only for the `ASTReader`'s internal use. Ok, fixed ================ Comment at: lib/Serialization/ASTReaderDecl.cpp:2369-2370 @@ +2368,4 @@ +void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitDecl(D); + D->setDeclName(Reader.ReadDeclarationName(F, Record, Idx)); + unsigned NumReductions = D->reductions_size(); ---------------- rsmith wrote: > Please call `VisitNamedDecl` instead of reimplementing it. Ok, fixed http://reviews.llvm.org/D11182 _______________________________________________ cfe-commits mailing list cfe-commits@cs.uiuc.edu http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits