llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Julian Brown (jtb20)
<details>
<summary>Changes</summary>
OpenMP 6.0 adds a 'saved' modifier to the data-environment
attribute clauses. On a 'firstprivate' clause it specifies that
the list item's value is captured when the surrounding construct
is recorded into a taskgraph, and that captured value is reused
(rather than re-evaluating the initialiser from the live original)
on every replay. See OpenMP 6.0 [7.5.4], [6.4.7] and [14.3].
This patch implements the front-end plumbing for the modifier:
parsing, AST representation and AST printing, profile, template
instantiation and PCH serialisation, modelled directly on the
existing 'lastprivate(conditional: ...)' machinery. No new
semantic restriction is added here (e.g. requiring a
taskgraph-nested or replayable task context), and codegen and the
runtime continue to treat 'saved' as a no-op for now -- those are
follow-up patches.
Specifically:
- OPENMP_FIRSTPRIVATE_KIND(saved) is added in OpenMPKinds.def,
with a matching OpenMPFirstprivateModifier enum and the
appropriate parse/print helpers in OpenMPKinds.cpp.
- OMPFirstprivateClause gains FPKind / FPKindLoc / ColonLoc
fields and an updated Create() signature; OMPClausePrinter
emits 'firstprivate(saved: ...)' when the modifier is set.
- ParseOpenMP recognises '[modifier:]' inside a firstprivate
clause when OpenMP >= 6.0.
- SemaOpenMP::ActOnOpenMPFirstprivateClause now takes the
modifier triple and diagnoses an unrecognised modifier via
the existing err_omp_unexpected_clause_value path; the
dispatcher in ActOnOpenMPVarListClause and the
implicit-firstprivate emitter in ActOnOpenMPRegionEnd are
updated accordingly.
- TreeTransform forwards the modifier through template
instantiation; ASTReader / ASTWriter round-trip the new
fields.
A new lit test taskgraph_firstprivate_saved_ast_print.cpp covers
ast-print and a PCH emit -> include -> ast-print round-trip on
'omp task' and 'omp taskloop' uses of firstprivate(saved: ...).
Assisted-By: Claude Opus 4.7
---
Full diff: https://github.com/llvm/llvm-project/pull/200406.diff
12 Files Affected:
- (modified) clang/include/clang/AST/OpenMPClause.h (+35-3)
- (modified) clang/include/clang/Basic/OpenMPKinds.def (+7)
- (modified) clang/include/clang/Basic/OpenMPKinds.h (+7)
- (modified) clang/include/clang/Sema/SemaOpenMP.h (+4-4)
- (modified) clang/lib/AST/OpenMPClause.cpp (+14-8)
- (modified) clang/lib/Basic/OpenMPKinds.cpp (+15-2)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+13)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+23-7)
- (modified) clang/lib/Sema/TreeTransform.h (+7-3)
- (modified) clang/lib/Serialization/ASTReader.cpp (+3)
- (modified) clang/lib/Serialization/ASTWriter.cpp (+3)
- (added) clang/test/OpenMP/taskgraph_firstprivate_saved_ast_print.cpp (+41)
``````````diff
diff --git a/clang/include/clang/AST/OpenMPClause.h
b/clang/include/clang/AST/OpenMPClause.h
index 34c0c47bfe710..30c9688f2fecf 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -3690,17 +3690,31 @@ class OMPFirstprivateClause final
friend OMPVarListClause;
friend TrailingObjects;
+ /// Optional firstprivate modifier (e.g. 'saved'), if specified by the user.
+ OpenMPFirstprivateModifier FPKind = OMPC_FIRSTPRIVATE_unknown;
+ /// Optional location of the firstprivate modifier, if specified.
+ SourceLocation FPKindLoc;
+ /// Optional location of the ':' separating the modifier from the list.
+ SourceLocation ColonLoc;
+
/// Build clause with number of variables \a N.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
+ /// \param FPKind Firstprivate modifier (e.g. 'saved').
+ /// \param FPKindLoc Location of the firstprivate modifier, if any.
+ /// \param ColonLoc Location of the ':' symbol, if a modifier is used.
/// \param N Number of the variables in the clause.
OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc, unsigned N)
+ SourceLocation EndLoc,
+ OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc, SourceLocation ColonLoc,
+ unsigned N)
: OMPVarListClause<OMPFirstprivateClause>(llvm::omp::OMPC_firstprivate,
StartLoc, LParenLoc, EndLoc,
N),
- OMPClauseWithPreInit(this) {}
+ OMPClauseWithPreInit(this), FPKind(FPKind), FPKindLoc(FPKindLoc),
+ ColonLoc(ColonLoc) {}
/// Build an empty clause.
///
@@ -3711,6 +3725,13 @@ class OMPFirstprivateClause final
SourceLocation(), N),
OMPClauseWithPreInit(this) {}
+ /// Sets the firstprivate modifier kind.
+ void setKind(OpenMPFirstprivateModifier Kind) { FPKind = Kind; }
+ /// Sets the location of the firstprivate modifier.
+ void setKindLoc(SourceLocation Loc) { FPKindLoc = Loc; }
+ /// Sets the location of the ':' separator.
+ void setColonLoc(SourceLocation Loc) { ColonLoc = Loc; }
+
/// Sets the list of references to private copies with initializers for
/// new private variables.
/// \param VL List of references.
@@ -3751,12 +3772,16 @@ class OMPFirstprivateClause final
/// \param InitVL List of references to auto generated variables used for
/// initialization of a single array element. Used if firstprivate variable
is
/// of array type.
+ /// \param FPKind Firstprivate modifier, e.g. 'saved'.
+ /// \param FPKindLoc Location of the firstprivate modifier, if any.
+ /// \param ColonLoc Location of the ':' symbol, if a modifier is used.
/// \param PreInit Statement that must be executed before entering the OpenMP
/// region with this clause.
static OMPFirstprivateClause *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation
LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *>
PrivateVL,
- ArrayRef<Expr *> InitVL, Stmt *PreInit);
+ ArrayRef<Expr *> InitVL, OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc, SourceLocation ColonLoc, Stmt *PreInit);
/// Creates an empty clause with the place for \a N variables.
///
@@ -3764,6 +3789,13 @@ class OMPFirstprivateClause final
/// \param N The number of variables.
static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N);
+ /// Firstprivate modifier (e.g. 'saved' if specified, otherwise 'unknown').
+ OpenMPFirstprivateModifier getKind() const { return FPKind; }
+ /// Returns the location of the firstprivate modifier, if any.
+ SourceLocation getKindLoc() const { return FPKindLoc; }
+ /// Returns the location of the ':' symbol, if any.
+ SourceLocation getColonLoc() const { return ColonLoc; }
+
using private_copies_iterator = MutableArrayRef<Expr *>::iterator;
using private_copies_const_iterator = ArrayRef<const Expr *>::iterator;
using private_copies_range = llvm::iterator_range<private_copies_iterator>;
diff --git a/clang/include/clang/Basic/OpenMPKinds.def
b/clang/include/clang/Basic/OpenMPKinds.def
index 3b79b940a1253..99ed68f8bce24 100644
--- a/clang/include/clang/Basic/OpenMPKinds.def
+++ b/clang/include/clang/Basic/OpenMPKinds.def
@@ -59,6 +59,9 @@
#ifndef OPENMP_DEVICE_TYPE_KIND
#define OPENMP_DEVICE_TYPE_KIND(Name)
#endif
+#ifndef OPENMP_FIRSTPRIVATE_KIND
+#define OPENMP_FIRSTPRIVATE_KIND(Name)
+#endif
#ifndef OPENMP_LASTPRIVATE_KIND
#define OPENMP_LASTPRIVATE_KIND(Name)
#endif
@@ -224,6 +227,9 @@ OPENMP_DEVICE_TYPE_KIND(host)
OPENMP_DEVICE_TYPE_KIND(nohost)
OPENMP_DEVICE_TYPE_KIND(any)
+// Type of the 'firstprivate' clause.
+OPENMP_FIRSTPRIVATE_KIND(saved)
+
// Type of the 'lastprivate' clause.
OPENMP_LASTPRIVATE_KIND(conditional)
@@ -304,6 +310,7 @@ OPENMP_USE_DEVICE_PTR_FALLBACK_MODIFIER(fb_preserve)
#undef OPENMP_ORIGINAL_SHARING_MODIFIER
#undef OPENMP_ORDER_KIND
#undef OPENMP_ORDER_MODIFIER
+#undef OPENMP_FIRSTPRIVATE_KIND
#undef OPENMP_LASTPRIVATE_KIND
#undef OPENMP_DEVICE_TYPE_KIND
#undef OPENMP_LINEAR_KIND
diff --git a/clang/include/clang/Basic/OpenMPKinds.h
b/clang/include/clang/Basic/OpenMPKinds.h
index 4e83bfcd0128b..47b4ef545b2c2 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -161,6 +161,13 @@ enum OpenMPDeviceType {
OMPC_DEVICE_TYPE_unknown
};
+/// OpenMP 'firstprivate' clause modifier.
+enum OpenMPFirstprivateModifier {
+#define OPENMP_FIRSTPRIVATE_KIND(Name) OMPC_FIRSTPRIVATE_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+ OMPC_FIRSTPRIVATE_unknown,
+};
+
/// OpenMP 'lastprivate' clause modifier.
enum OpenMPLastprivateModifier {
#define OPENMP_LASTPRIVATE_KIND(Name) OMPC_LASTPRIVATE_##Name,
diff --git a/clang/include/clang/Sema/SemaOpenMP.h
b/clang/include/clang/Sema/SemaOpenMP.h
index 98405b871641a..54f6a5dcaca24 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -1269,10 +1269,10 @@ class SemaOpenMP : public SemaBase {
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'firstprivate' clause.
- OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc);
+ OMPClause *ActOnOpenMPFirstprivateClause(
+ ArrayRef<Expr *> VarList, OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc, SourceLocation ColonLoc,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation
EndLoc);
/// Called on well-formed 'lastprivate' clause.
OMPClause *ActOnOpenMPLastprivateClause(
ArrayRef<Expr *> VarList, OpenMPLastprivateModifier LPKind,
diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp
index 7d2b4aa64a1df..de82e23878a25 100644
--- a/clang/lib/AST/OpenMPClause.cpp
+++ b/clang/lib/AST/OpenMPClause.cpp
@@ -493,14 +493,14 @@ void OMPFirstprivateClause::setInits(ArrayRef<Expr *> VL)
{
llvm::copy(VL, getPrivateCopies().end());
}
-OMPFirstprivateClause *
-OMPFirstprivateClause::Create(const ASTContext &C, SourceLocation StartLoc,
- SourceLocation LParenLoc, SourceLocation EndLoc,
- ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
- ArrayRef<Expr *> InitVL, Stmt *PreInit) {
+OMPFirstprivateClause *OMPFirstprivateClause::Create(
+ const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
+ SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> PrivateVL,
+ ArrayRef<Expr *> InitVL, OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc, SourceLocation ColonLoc, Stmt *PreInit) {
void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(3 * VL.size()));
- OMPFirstprivateClause *Clause =
- new (Mem) OMPFirstprivateClause(StartLoc, LParenLoc, EndLoc, VL.size());
+ OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(
+ StartLoc, LParenLoc, EndLoc, FPKind, FPKindLoc, ColonLoc, VL.size());
Clause->setVarRefs(VL);
Clause->setPrivateCopies(PrivateVL);
Clause->setInits(InitVL);
@@ -2563,7 +2563,13 @@ void
OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) {
void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node)
{
if (!Node->varlist_empty()) {
OS << "firstprivate";
- VisitOMPClauseList(Node, '(');
+ OpenMPFirstprivateModifier FPKind = Node->getKind();
+ if (FPKind != OMPC_FIRSTPRIVATE_unknown) {
+ OS << "("
+ << getOpenMPSimpleClauseTypeName(OMPC_firstprivate, Node->getKind())
+ << ":";
+ }
+ VisitOMPClauseList(Node, FPKind == OMPC_FIRSTPRIVATE_unknown ? '(' : ' ');
OS << ")";
}
}
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 7cca74ffe711d..cb55989edda2d 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -149,6 +149,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind
Kind, StringRef Str,
#define OPENMP_SEVERITY_KIND(Name) .Case(#Name, OMPC_SEVERITY_##Name)
#include "clang/Basic/OpenMPKinds.def"
.Default(OMPC_SEVERITY_unknown);
+ case OMPC_firstprivate:
+ return llvm::StringSwitch<OpenMPFirstprivateModifier>(Str)
+#define OPENMP_FIRSTPRIVATE_KIND(Name) .Case(#Name, OMPC_FIRSTPRIVATE_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+ .Default(OMPC_FIRSTPRIVATE_unknown);
case OMPC_lastprivate:
return llvm::StringSwitch<OpenMPLastprivateModifier>(Str)
#define OPENMP_LASTPRIVATE_KIND(Name) .Case(#Name, OMPC_LASTPRIVATE_##Name)
@@ -261,7 +266,6 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind
Kind, StringRef Str,
case OMPC_allocator:
case OMPC_collapse:
case OMPC_private:
- case OMPC_firstprivate:
case OMPC_shared:
case OMPC_task_reduction:
case OMPC_in_reduction:
@@ -477,6 +481,16 @@ const char
*clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
#include "clang/Basic/OpenMPKinds.def"
}
llvm_unreachable("Invalid OpenMP 'severity' clause type");
+ case OMPC_firstprivate:
+ switch (Type) {
+ case OMPC_FIRSTPRIVATE_unknown:
+ return "unknown";
+#define OPENMP_FIRSTPRIVATE_KIND(Name)
\
+ case OMPC_FIRSTPRIVATE_##Name:
\
+ return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+ }
+ llvm_unreachable("Invalid OpenMP 'firstprivate' clause type");
case OMPC_lastprivate:
switch (Type) {
case OMPC_LASTPRIVATE_unknown:
@@ -643,7 +657,6 @@ const char
*clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
case OMPC_allocator:
case OMPC_collapse:
case OMPC_private:
- case OMPC_firstprivate:
case OMPC_shared:
case OMPC_task_reduction:
case OMPC_in_reduction:
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 1338001b73b30..91b0f2e739f77 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -4939,6 +4939,19 @@ bool Parser::ParseOpenMPVarList(OpenMPDirectiveKind
DKind,
<< "linear-modifier(list)" << getOpenMPClauseName(Kind)
<< "linear(list: [linear-modifier,] step(step-size))";
}
+ } else if (Kind == OMPC_firstprivate) {
+ // Try to parse modifier if any.
+ Data.ExtraModifier = OMPC_FIRSTPRIVATE_unknown;
+ // The 'saved' modifier is OpenMP 6.0+ only.
+ if (getLangOpts().OpenMP >= 60 && Tok.is(tok::identifier) &&
+ PP.LookAhead(0).is(tok::colon)) {
+ Data.ExtraModifier =
+ getOpenMPSimpleClauseType(Kind, PP.getSpelling(Tok), getLangOpts());
+ Data.ExtraModifierLoc = Tok.getLocation();
+ ConsumeToken();
+ assert(Tok.is(tok::colon) && "Expected colon.");
+ Data.ColonLoc = ConsumeToken();
+ }
} else if (Kind == OMPC_lastprivate) {
// Try to parse modifier if any.
Data.ExtraModifier = OMPC_LASTPRIVATE_unknown;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index c1bf6671cfdec..51a5c3522a5db 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6378,8 +6378,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
}
if (!ImpInfo.Firstprivates.empty()) {
if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause(
- ImpInfo.Firstprivates.getArrayRef(), SourceLocation(),
- SourceLocation(), SourceLocation())) {
+ ImpInfo.Firstprivates.getArrayRef(), OMPC_FIRSTPRIVATE_unknown,
+ /*FPKindLoc=*/SourceLocation(), /*ColonLoc=*/SourceLocation(),
+ /*StartLoc=*/SourceLocation(), /*LParenLoc=*/SourceLocation(),
+ /*EndLoc=*/SourceLocation())) {
ClausesWithImplicit.push_back(Implicit);
ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() !=
ImpInfo.Firstprivates.size();
@@ -19248,7 +19250,11 @@ OMPClause
*SemaOpenMP::ActOnOpenMPVarListClause(OpenMPClauseKind Kind,
Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_firstprivate:
- Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc);
+ assert(0 <= ExtraModifier && ExtraModifier <= OMPC_FIRSTPRIVATE_unknown &&
+ "Unexpected firstprivate modifier.");
+ Res = ActOnOpenMPFirstprivateClause(
+ VarList, static_cast<OpenMPFirstprivateModifier>(ExtraModifier),
+ ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_lastprivate:
assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LASTPRIVATE_unknown &&
@@ -19629,10 +19635,19 @@ OMPClause
*SemaOpenMP::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
Vars, PrivateCopies);
}
-OMPClause *SemaOpenMP::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
- SourceLocation StartLoc,
- SourceLocation LParenLoc,
- SourceLocation EndLoc) {
+OMPClause *SemaOpenMP::ActOnOpenMPFirstprivateClause(
+ ArrayRef<Expr *> VarList, OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc, SourceLocation ColonLoc, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ if (FPKind == OMPC_FIRSTPRIVATE_unknown && FPKindLoc.isValid()) {
+ assert(ColonLoc.isValid() && "Colon location must be valid.");
+ Diag(FPKindLoc, diag::err_omp_unexpected_clause_value)
+ << getListOfPossibleValues(OMPC_firstprivate, /*First=*/0,
+ /*Last=*/OMPC_FIRSTPRIVATE_unknown)
+ << getOpenMPClauseNameForDiag(OMPC_firstprivate);
+ return nullptr;
+ }
+
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
@@ -19918,6 +19933,7 @@ OMPClause
*SemaOpenMP::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
return OMPFirstprivateClause::Create(
getASTContext(), StartLoc, LParenLoc, EndLoc, Vars, PrivateCopies, Inits,
+ FPKind, FPKindLoc, ColonLoc,
buildPreInits(getASTContext(), ExprCaptures));
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 07812bd8074f9..e0ea135fcf557 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -1932,11 +1932,14 @@ class TreeTransform {
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList,
+ OpenMPFirstprivateModifier FPKind,
+ SourceLocation FPKindLoc,
+ SourceLocation ColonLoc,
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
- return getSema().OpenMP().ActOnOpenMPFirstprivateClause(VarList, StartLoc,
- LParenLoc, EndLoc);
+ return getSema().OpenMP().ActOnOpenMPFirstprivateClause(
+ VarList, FPKind, FPKindLoc, ColonLoc, StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'lastprivate' clause.
@@ -11220,7 +11223,8 @@ OMPClause
*TreeTransform<Derived>::TransformOMPFirstprivateClause(
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPFirstprivateClause(
- Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc());
+ Vars, C->getKind(), C->getKindLoc(), C->getColonLoc(), C->getBeginLoc(),
+ C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp
b/clang/lib/Serialization/ASTReader.cpp
index a1f53a2c742c2..f681f6d47c7e7 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -12196,6 +12196,9 @@ void
OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) {
void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
VisitOMPClauseWithPreInit(C);
C->setLParenLoc(Record.readSourceLocation());
+ C->setKind(Record.readEnum<OpenMPFirstprivateModifier>());
+ C->setKindLoc(Record.readSourceLocation());
+ C->setColonLoc(Record.readSourceLocation());
unsigned NumVars = C->varlist_size();
SmallVector<Expr *, 16> Vars;
Vars.reserve(NumVars);
diff --git a/clang/lib/Serialization/ASTWriter.cpp
b/clang/lib/Serialization/ASTWriter.cpp
index 20e981b9da3b5..faf59d25a87c4 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -8308,6 +8308,9 @@ void
OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) {
Record.push_back(C->varlist_size());
VisitOMPClauseWithPreInit(C);
Record.AddSourceLocation(C->getLParenLoc());
+ Record.writeEnum(C->getKind());
+ Record.AddSourceLocation(C->getKindLoc());
+ Record.AddSourceLocation(C->getColonLoc());
for (auto *VE : C->varlist()) {
Record.AddStmt(VE);
}
diff --git a/clang/test/OpenMP/taskgraph_firstprivate_saved_ast_print.cpp
b/clang/test/OpenMP/taskgraph_firstprivate_saved_ast_print.cpp
new file mode 100644
index 0000000000000..faf6b7a2936ae
--- /dev/null
+++ b/clang/test/OpenMP/taskgraph_firstprivate_saved_ast_print.cpp
@@ -0,0 +1,41 @@
+// Check no warnings/errors
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60
-fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Check unparsing
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60
-ast-print %s | FileCheck %s
+
+// Check same results after serialization round-trip
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60
-emit-pch -o %t %s
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-version=60
-include-pch %t -ast-print %s | FileCheck %s
+
+#ifndef HEADER
+#define HEADER
+
+void firstprivate_saved() {
+ int a = 1;
+ int b = 2;
+ int c = 3;
+
+ // CHECK: #pragma omp task firstprivate(a)
+ #pragma omp task firstprivate(a)
+ { (void)a; }
+
+ // CHECK: #pragma omp task firstprivate(saved: a)
+ #pragma omp task firstprivate(saved: a)
+ { (void)a; }
+
+ // CHECK: #pragma omp task firstprivate(saved: a,b,c)
+ #pragma omp task firstprivate(saved: a, b, c)
+ { (void)a; (void)b; (void)c; }
+
+ // CHECK: #pragma omp task firstprivate(saved: a) shared(b)
+ #pragma omp task firstprivate(saved: a) shared(b)
+ { (void)a; (void)b; }
+
+ // CHECK: #pragma omp taskloop firstprivate(saved: a)
+ #pragma omp taskloop firstprivate(saved: a)
+ for (int i = 0; i < 4; ++i) (void)a;
+}
+
+#endif
``````````
</details>
https://github.com/llvm/llvm-project/pull/200406
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits