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

Reply via email to