From f7de5eb2e62f77f2f6a7a3944f8b5a6fe85a25da Mon Sep 17 00:00:00 2001
From: Philippe Virouleau <philippe.virouleau@imag.fr>
Date: Tue, 29 Mar 2016 14:18:28 +0200
Subject: [PATCH] Added 'init' clause to parallel directive.

This specifies an algorithm for the initial ready tasks in the parallel section.
---
 include/clang/AST/OpenMPClause.h        | 73 +++++++++++++++++++++++++
 include/clang/AST/RecursiveASTVisitor.h |  5 ++
 include/clang/Basic/OpenMPKinds.def     | 14 +++++
 include/clang/Basic/OpenMPKinds.h       |  8 +++
 include/clang/Sema/Sema.h               |  7 +++
 lib/AST/OpenMPClause.cpp                |  4 ++
 lib/AST/StmtPrinter.cpp                 |  6 ++
 lib/AST/StmtProfile.cpp                 |  2 +
 lib/Basic/OpenMPKinds.cpp               | 15 +++++
 lib/CodeGen/CGOpenMPRuntime.cpp         | 67 +++++++++++++++++++++++
 lib/CodeGen/CGOpenMPRuntime.h           |  9 +++
 lib/CodeGen/CGStmtOpenMP.cpp            | 15 +++++
 lib/Parse/ParseOpenMP.cpp               | 11 ++++
 lib/Sema/SemaOpenMP.cpp                 | 25 +++++++++
 lib/Sema/TreeTransform.h                | 21 +++++++
 lib/Serialization/ASTReaderStmt.cpp     | 10 ++++
 lib/Serialization/ASTWriterStmt.cpp     |  6 ++
 tools/libclang/CIndex.cpp               |  2 +
 18 files changed, 300 insertions(+)

diff --git a/include/clang/AST/OpenMPClause.h b/include/clang/AST/OpenMPClause.h
index 209c255acee..2a20fdb854e 100644
--- a/include/clang/AST/OpenMPClause.h
+++ b/include/clang/AST/OpenMPClause.h
@@ -614,6 +614,79 @@ public:
   }
 };
 
+/// \brief This represents 'init' clause in the '#pragma omp paralle ...'
+/// directive.
+///
+/// \code
+/// #pragma omp parallel init(cyclicnuma)
+/// \endcode
+/// In this example directive '#pragma omp parallel' has simple 'init'
+/// clause with kind 'cyclicnuma'.
+///
+class OMPInitClause : public OMPClause {
+  friend class OMPClauseReader;
+  /// \brief Location of '('.
+  SourceLocation LParenLoc;
+  /// \brief A kind of the 'init' clause.
+  OpenMPInitClauseKind Kind;
+  /// \brief Start location of the kind in source code.
+  SourceLocation KindKwLoc;
+
+  /// \brief Set kind of the clause.
+  ///
+  /// \param K Kind of clause.
+  ///
+  void setInitKind(OpenMPInitClauseKind K) { Kind = K; }
+
+  /// \brief Set clause kind location.
+  ///
+  /// \param KLoc Kind location.
+  ///
+  void setInitKindKwLoc(SourceLocation KLoc) { KindKwLoc = KLoc; }
+
+public:
+  /// \brief Build 'init' clause with argument \a A ('runtime', 'rand', 'cyclic',
+  ///        'randnuma', 'cyclicnuma' or 'cyclicnumastrict').
+  ///
+  /// \param A Argument of the clause (eg : 'runtime', 'rand').
+  /// \param ALoc Starting location of the argument.
+  /// \param StartLoc Starting location of the clause.
+  /// \param LParenLoc Location of '('.
+  /// \param EndLoc Ending location of the clause.
+  ///
+  OMPInitClause(OpenMPInitClauseKind A, SourceLocation ALoc,
+                    SourceLocation StartLoc, SourceLocation LParenLoc,
+                    SourceLocation EndLoc)
+      : OMPClause(OMPC_init, StartLoc, EndLoc), LParenLoc(LParenLoc),
+        Kind(A), KindKwLoc(ALoc) {}
+
+  /// \brief Build an empty clause.
+  ///
+  OMPInitClause()
+      : OMPClause(OMPC_init, SourceLocation(), SourceLocation()),
+        LParenLoc(SourceLocation()), Kind(OMPC_INIT_unknown),
+        KindKwLoc(SourceLocation()) {}
+
+  /// \brief Sets the location of '('.
+  void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
+  /// \brief Returns the location of '('.
+  SourceLocation getLParenLoc() const { return LParenLoc; }
+
+  /// \brief Returns kind of the clause.
+  OpenMPInitClauseKind getInitKind() const { return Kind; }
+
+  /// \brief Returns location of clause kind.
+  SourceLocation getInitKindKwLoc() const { return KindKwLoc; }
+
+  static bool classof(const OMPClause *T) {
+    return T->getClauseKind() == OMPC_init;
+  }
+
+  child_range children() {
+    return child_range(child_iterator(), child_iterator());
+  }
+};
+
 /// \brief This represents 'proc_bind' clause in the '#pragma omp ...'
 /// directive.
 ///
diff --git a/include/clang/AST/RecursiveASTVisitor.h b/include/clang/AST/RecursiveASTVisitor.h
index c4bfdc98a7a..99a08f67d79 100644
--- a/include/clang/AST/RecursiveASTVisitor.h
+++ b/include/clang/AST/RecursiveASTVisitor.h
@@ -2656,6 +2656,11 @@ bool RecursiveASTVisitor<Derived>::VisitOMPProcBindClause(OMPProcBindClause *) {
   return true;
 }
 
+template <typename Derived>
+bool RecursiveASTVisitor<Derived>::VisitOMPInitClause(OMPInitClause *) {
+  return true;
+}
+
 template <typename Derived>
 bool
 RecursiveASTVisitor<Derived>::VisitOMPScheduleClause(OMPScheduleClause *C) {
diff --git a/include/clang/Basic/OpenMPKinds.def b/include/clang/Basic/OpenMPKinds.def
index d9fc5391c48..6894e7cf0c4 100644
--- a/include/clang/Basic/OpenMPKinds.def
+++ b/include/clang/Basic/OpenMPKinds.def
@@ -102,6 +102,9 @@
 #ifndef OPENMP_PROC_BIND_KIND
 #  define OPENMP_PROC_BIND_KIND(Name)
 #endif
+#ifndef OPENMP_INIT_KIND
+#define OPENMP_INIT_KIND(Name)
+#endif
 #ifndef OPENMP_SCHEDULE_KIND
 #define OPENMP_SCHEDULE_KIND(Name)
 #endif
@@ -231,12 +234,14 @@ OPENMP_CLAUSE(from, OMPFromClause)
 OPENMP_CLAUSE(use_device_ptr, OMPUseDevicePtrClause)
 OPENMP_CLAUSE(is_device_ptr, OMPIsDevicePtrClause)
 OPENMP_CLAUSE(affinity, OMPAffinityClause)
+OPENMP_CLAUSE(init, OMPInitClause)
 
 // Clauses allowed for OpenMP directive 'parallel'.
 OPENMP_PARALLEL_CLAUSE(if)
 OPENMP_PARALLEL_CLAUSE(num_threads)
 OPENMP_PARALLEL_CLAUSE(default)
 OPENMP_PARALLEL_CLAUSE(proc_bind)
+OPENMP_PARALLEL_CLAUSE(init)
 OPENMP_PARALLEL_CLAUSE(private)
 OPENMP_PARALLEL_CLAUSE(firstprivate)
 OPENMP_PARALLEL_CLAUSE(shared)
@@ -310,6 +315,14 @@ OPENMP_SCHEDULE_KIND(guided)
 OPENMP_SCHEDULE_KIND(auto)
 OPENMP_SCHEDULE_KIND(runtime)
 
+// Static attributes for 'init' clause.
+OPENMP_INIT_KIND(runtime)
+OPENMP_INIT_KIND(rand)
+OPENMP_INIT_KIND(cyclic)
+OPENMP_INIT_KIND(randnuma)
+OPENMP_INIT_KIND(cyclicnuma)
+OPENMP_INIT_KIND(cyclicnumastrict)
+
 // Modifiers for 'schedule' clause.
 OPENMP_SCHEDULE_MODIFIER(monotonic)
 OPENMP_SCHEDULE_MODIFIER(nonmonotonic)
@@ -628,6 +641,7 @@ OPENMP_TARGET_PARALLEL_FOR_SIMD_CLAUSE(aligned)
 #undef OPENMP_DEPEND_KIND
 #undef OPENMP_SCHEDULE_MODIFIER
 #undef OPENMP_SCHEDULE_KIND
+#undef OPENMP_INIT_KIND
 #undef OPENMP_PROC_BIND_KIND
 #undef OPENMP_DEFAULT_KIND
 #undef OPENMP_DIRECTIVE
diff --git a/include/clang/Basic/OpenMPKinds.h b/include/clang/Basic/OpenMPKinds.h
index 0a8e890b7c4..285ce0b5d8b 100644
--- a/include/clang/Basic/OpenMPKinds.h
+++ b/include/clang/Basic/OpenMPKinds.h
@@ -55,6 +55,14 @@ enum OpenMPProcBindClauseKind {
   OMPC_PROC_BIND_unknown
 };
 
+/// \brief OpenMP attributes for 'init' clause.
+enum OpenMPInitClauseKind {
+#define OPENMP_INIT_KIND(Name) \
+  OMPC_INIT_##Name,
+#include "clang/Basic/OpenMPKinds.def"
+  OMPC_INIT_unknown
+};
+
 /// \brief OpenMP attributes for 'schedule' clause.
 enum OpenMPScheduleClauseKind {
 #define OPENMP_SCHEDULE_KIND(Name) \
diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h
index 722e4bf1d0b..e713067733a 100644
--- a/include/clang/Sema/Sema.h
+++ b/include/clang/Sema/Sema.h
@@ -8333,6 +8333,13 @@ public:
                                        SourceLocation LParenLoc,
                                        SourceLocation EndLoc);
 
+  /// \brief Called on well-formed 'init' clause.
+  OMPClause *ActOnOpenMPInitClause(OpenMPInitClauseKind Kind,
+                                       SourceLocation KindLoc,
+                                       SourceLocation StartLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation EndLoc);
+
   OMPClause *ActOnOpenMPSingleExprWithArgClause(
       OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,
       SourceLocation StartLoc, SourceLocation LParenLoc,
diff --git a/lib/AST/OpenMPClause.cpp b/lib/AST/OpenMPClause.cpp
index d04ba727bb0..3f87b900123 100644
--- a/lib/AST/OpenMPClause.cpp
+++ b/lib/AST/OpenMPClause.cpp
@@ -80,6 +80,8 @@ const OMPClauseWithPreInit *OMPClauseWithPreInit::get(const OMPClause *C) {
   case OMPC_num_teams:
   case OMPC_thread_limit:
   case OMPC_priority:
+  case OMPC_affinity:
+  case OMPC_init:
   case OMPC_grainsize:
   case OMPC_nogroup:
   case OMPC_num_tasks:
@@ -145,6 +147,8 @@ const OMPClauseWithPostUpdate *OMPClauseWithPostUpdate::get(const OMPClause *C)
   case OMPC_num_teams:
   case OMPC_thread_limit:
   case OMPC_priority:
+  case OMPC_affinity:
+  case OMPC_init:
   case OMPC_grainsize:
   case OMPC_nogroup:
   case OMPC_num_tasks:
diff --git a/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp
index 116ddde7348..6057b227e23 100644
--- a/lib/AST/StmtPrinter.cpp
+++ b/lib/AST/StmtPrinter.cpp
@@ -656,6 +656,12 @@ void OMPClausePrinter::VisitOMPProcBindClause(OMPProcBindClause *Node) {
      << ")";
 }
 
+void OMPClausePrinter::VisitOMPInitClause(OMPInitClause *Node) {
+  OS << "init("
+     << getOpenMPSimpleClauseTypeName(OMPC_init, Node->getInitKind())
+     << ")";
+}
+
 void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) {
   OS << "schedule(";
   if (Node->getFirstScheduleModifier() != OMPC_SCHEDULE_MODIFIER_unknown) {
diff --git a/lib/AST/StmtProfile.cpp b/lib/AST/StmtProfile.cpp
index f13c885b259..8a3daa128dd 100644
--- a/lib/AST/StmtProfile.cpp
+++ b/lib/AST/StmtProfile.cpp
@@ -320,6 +320,8 @@ void OMPClauseProfiler::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
 
 void OMPClauseProfiler::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
 
+void OMPClauseProfiler::VisitOMPInitClause(const OMPInitClause *C) { }
+
 void OMPClauseProfiler::VisitOMPScheduleClause(const OMPScheduleClause *C) {
   VistOMPClauseWithPreInit(C);
   if (auto *S = C->getChunkSize())
diff --git a/lib/Basic/OpenMPKinds.cpp b/lib/Basic/OpenMPKinds.cpp
index 503db60f561..3bf9f113c89 100644
--- a/lib/Basic/OpenMPKinds.cpp
+++ b/lib/Basic/OpenMPKinds.cpp
@@ -89,6 +89,11 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind,
 #define OPENMP_PROC_BIND_KIND(Name) .Case(#Name, OMPC_PROC_BIND_##Name)
 #include "clang/Basic/OpenMPKinds.def"
         .Default(OMPC_PROC_BIND_unknown);
+  case OMPC_init:
+    return llvm::StringSwitch<OpenMPInitClauseKind>(Str)
+#define OPENMP_INIT_KIND(Name) .Case(#Name, OMPC_INIT_##Name)
+#include "clang/Basic/OpenMPKinds.def"
+        .Default(OMPC_INIT_unknown);
   case OMPC_schedule:
     return llvm::StringSwitch<unsigned>(Str)
 #define OPENMP_SCHEDULE_KIND(Name)                                             \
@@ -195,6 +200,16 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind,
 #include "clang/Basic/OpenMPKinds.def"
     }
     llvm_unreachable("Invalid OpenMP 'proc_bind' clause type");
+  case OMPC_init:
+    switch (Type) {
+    case OMPC_INIT_unknown:
+      return "unknown";
+#define OPENMP_INIT_KIND(Name)                                            \
+  case OMPC_INIT_##Name:                                                  \
+    return #Name;
+#include "clang/Basic/OpenMPKinds.def"
+    }
+    llvm_unreachable("Invalid OpenMP 'init' clause type");
   case OMPC_schedule:
     switch (Type) {
     case OMPC_SCHEDULE_unknown:
diff --git a/lib/CodeGen/CGOpenMPRuntime.cpp b/lib/CodeGen/CGOpenMPRuntime.cpp
index ee692d27ae1..36a29e91919 100644
--- a/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -557,6 +557,10 @@ enum OpenMPRTLFunction {
   OMPRTL__kmpc_omp_taskyield,
   // Call to void __kmpc_omp_set_task_affinity(ident_t *, kmp_int32 affinity);
   OMPRTL__kmpc_omp_set_task_affinity,
+  // Call to void __kmpc_begin_push_init(int kind);
+  OMPRTL__kmpc_begin_push_init,
+  // Call to void __kmpc_end_push_init();
+  OMPRTL__kmpc_end_push_init,
   // Call to kmp_int32 __kmpc_single(ident_t *, kmp_int32 global_tid);
   OMPRTL__kmpc_single,
   // Call to void __kmpc_end_single(ident_t *, kmp_int32 global_tid);
@@ -1419,6 +1423,21 @@ CGOpenMPRuntime::createRuntimeFunction(unsigned Function) {
     RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_push_proc_bind");
     break;
   }
+  case OMPRTL__kmpc_begin_push_init: {
+    // Build void __kmpc_begin_push_init(int init_kind)
+    llvm::Type *TypeParams[] = {CGM.IntTy};
+    llvm::FunctionType *FnTy =
+        llvm::FunctionType::get(CGM.VoidTy, TypeParams, /*isVarArg*/ false);
+    RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_begin_push_init");
+    break;
+  }
+  case OMPRTL__kmpc_end_push_init: {
+    // Build void __kmpc_end_push_init()
+    llvm::FunctionType *FnTy =
+        llvm::FunctionType::get(CGM.VoidTy, /*isVarArg*/ false);
+    RTLFn = CGM.CreateRuntimeFunction(FnTy, "__kmpc_end_push_init");
+    break;
+  }
   case OMPRTL__kmpc_omp_task_with_deps: {
     // Build kmp_int32 __kmpc_omp_task_with_deps(ident_t *, kmp_int32 gtid,
     // kmp_task_t *new_task, kmp_int32 ndeps, kmp_depend_info_t *dep_list,
@@ -2661,6 +2680,54 @@ void CGOpenMPRuntime::emitProcBindClause(CodeGenFunction &CGF,
   CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_push_proc_bind), Args);
 }
 
+void CGOpenMPRuntime::emitBeginInitClause(CodeGenFunction &CGF,
+                                          OpenMPInitClauseKind Init) {
+  if (!CGF.HaveInsertPoint())
+    return;
+  // Constants for proc bind value accepted by the runtime.
+  enum InitTy {
+    InitRuntime = 0,
+    InitRand,
+    InitCyclic,
+    InitRandNuma,
+    InitCyclicNuma,
+    InitCyclicNumaStrict
+  } RuntimeInit;
+  switch (Init) {
+  case OMPC_INIT_runtime:
+    RuntimeInit = InitRuntime;
+    break;
+  case OMPC_INIT_rand:
+    RuntimeInit = InitRand;
+    break;
+  case OMPC_INIT_cyclic:
+    RuntimeInit = InitCyclic;
+    break;
+  case OMPC_INIT_randnuma:
+    RuntimeInit = InitRandNuma;
+    break;
+  case OMPC_INIT_cyclicnuma:
+    RuntimeInit = InitCyclicNuma;
+    break;
+  case OMPC_INIT_cyclicnumastrict:
+    RuntimeInit = InitCyclicNumaStrict;
+    break;
+  case OMPC_INIT_unknown:
+    llvm_unreachable("Unsupported init value.");
+  }
+  // Build call __kmpc_begin_push_init(init)
+  llvm::Value *Args[] = {
+      llvm::ConstantInt::get(CGM.IntTy, RuntimeInit, /*isSigned=*/true)};
+  CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_begin_push_init), Args);
+}
+
+void CGOpenMPRuntime::emitEndInitClause(CodeGenFunction &CGF) {
+  if (!CGF.HaveInsertPoint())
+    return;
+  // Build call __kmpc_end_push_init(init)
+  CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_end_push_init));
+}
+
 void CGOpenMPRuntime::emitFlush(CodeGenFunction &CGF, ArrayRef<const Expr *>,
                                 SourceLocation Loc) {
   if (!CGF.HaveInsertPoint())
diff --git a/lib/CodeGen/CGOpenMPRuntime.h b/lib/CodeGen/CGOpenMPRuntime.h
index 270de8dd505..1f62bf1e9fe 100644
--- a/lib/CodeGen/CGOpenMPRuntime.h
+++ b/lib/CodeGen/CGOpenMPRuntime.h
@@ -749,6 +749,15 @@ public:
                                   OpenMPProcBindClauseKind ProcBind,
                                   SourceLocation Loc);
 
+  /// \brief Emit call to void __kmpc_begin_push_init(int init)
+  /// to generate code for begin 'init' clause.
+  virtual void emitBeginInitClause(CodeGenFunction &CGF,
+                                   OpenMPInitClauseKind Init);
+
+  /// \brief Emit call to void __kmpc_end_push_init()
+  /// to generate code for end 'init' clause.
+  virtual void emitEndInitClause(CodeGenFunction &CGF);
+
   /// \brief Returns address of the threadprivate variable for the current
   /// thread.
   /// \param VD Threadprivate variable.
diff --git a/lib/CodeGen/CGStmtOpenMP.cpp b/lib/CodeGen/CGStmtOpenMP.cpp
index f7ba30efc2d..678de8369aa 100644
--- a/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/lib/CodeGen/CGStmtOpenMP.cpp
@@ -1232,8 +1232,22 @@ static void emitCommonOMPParallelDirective(CodeGenFunction &CGF,
   OMPLexicalScope Scope(CGF, S);
   llvm::SmallVector<llvm::Value *, 16> CapturedVars;
   CGF.GenerateOpenMPCapturedVars(*CS, CapturedVars);
+
+  if (const auto *InitClause = S.getSingleClause<OMPInitClause>()) {
+    llvm::errs() << "Got an init : " <<
+      getOpenMPSimpleClauseTypeName(OMPC_init, InitClause->getInitKind()) << "\n";
+    CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
+    CGF.CGM.getOpenMPRuntime().emitBeginInitClause(
+        CGF, InitClause->getInitKind());
+  }
+
   CGF.CGM.getOpenMPRuntime().emitParallelCall(CGF, S.getLocStart(), OutlinedFn,
                                               CapturedVars, IfCond);
+
+  if (const auto *InitClause = S.getSingleClause<OMPInitClause>()) {
+    CodeGenFunction::RunCleanupsScope NumThreadsScope(CGF);
+    CGF.CGM.getOpenMPRuntime().emitEndInitClause(CGF);
+  }
 }
 
 void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) {
@@ -3220,6 +3234,7 @@ static void EmitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
   case OMPC_copyprivate:
   case OMPC_flush:
   case OMPC_proc_bind:
+  case OMPC_init:
   case OMPC_schedule:
   case OMPC_ordered:
   case OMPC_nowait:
diff --git a/lib/Parse/ParseOpenMP.cpp b/lib/Parse/ParseOpenMP.cpp
index aadcb631a3e..f81938486ba 100644
--- a/lib/Parse/ParseOpenMP.cpp
+++ b/lib/Parse/ParseOpenMP.cpp
@@ -1133,6 +1133,17 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
       ErrorFound = true;
     }
 
+    Clause = ParseOpenMPSimpleClause(CKind);
+    break;
+  case OMPC_init:
+    // Extension
+    //  At most one init clause can appear on the directive.
+    if (!FirstClause) {
+      Diag(Tok, diag::err_omp_more_one_clause)
+          << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
+      ErrorFound = true;
+    }
+
     Clause = ParseOpenMPSimpleClause(CKind);
     break;
   case OMPC_schedule:
diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp
index 8214b78c3f4..315d830c684 100644
--- a/lib/Sema/SemaOpenMP.cpp
+++ b/lib/Sema/SemaOpenMP.cpp
@@ -7258,6 +7258,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
   case OMPC_if:
   case OMPC_default:
   case OMPC_proc_bind:
+  case OMPC_init:
   case OMPC_schedule:
   case OMPC_private:
   case OMPC_firstprivate:
@@ -7532,6 +7533,11 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
         static_cast<OpenMPProcBindClauseKind>(Argument), ArgumentLoc, StartLoc,
         LParenLoc, EndLoc);
     break;
+  case OMPC_init:
+    Res = ActOnOpenMPInitClause(
+        static_cast<OpenMPInitClauseKind>(Argument), ArgumentLoc, StartLoc,
+        LParenLoc, EndLoc);
+    break;
   case OMPC_if:
   case OMPC_final:
   case OMPC_num_threads:
@@ -7653,6 +7659,22 @@ OMPClause *Sema::ActOnOpenMPProcBindClause(OpenMPProcBindClauseKind Kind,
       OMPProcBindClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
 }
 
+OMPClause *Sema::ActOnOpenMPInitClause(OpenMPInitClauseKind Kind,
+                                       SourceLocation KindKwLoc,
+                                       SourceLocation StartLoc,
+                                       SourceLocation LParenLoc,
+                                       SourceLocation EndLoc) {
+  if (Kind == OMPC_INIT_unknown) {
+    Diag(KindKwLoc, diag::err_omp_unexpected_clause_value)
+        << getListOfPossibleValues(OMPC_init, /*First=*/0,
+                                   /*Last=*/OMPC_INIT_unknown)
+        << getOpenMPClauseName(OMPC_init);
+    return nullptr;
+  }
+  return new (Context)
+      OMPInitClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc);
+}
+
 OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
     OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr,
     SourceLocation StartLoc, SourceLocation LParenLoc,
@@ -7697,6 +7719,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
   case OMPC_collapse:
   case OMPC_default:
   case OMPC_proc_bind:
+  case OMPC_init:
   case OMPC_private:
   case OMPC_firstprivate:
   case OMPC_lastprivate:
@@ -7906,6 +7929,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
   case OMPC_copyprivate:
   case OMPC_default:
   case OMPC_proc_bind:
+  case OMPC_init:
   case OMPC_threadprivate:
   case OMPC_flush:
   case OMPC_depend:
@@ -8059,6 +8083,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
   case OMPC_collapse:
   case OMPC_default:
   case OMPC_proc_bind:
+  case OMPC_init:
   case OMPC_schedule:
   case OMPC_ordered:
   case OMPC_nowait:
diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h
index 752b7629b7f..47f856cd032 100644
--- a/lib/Sema/TreeTransform.h
+++ b/lib/Sema/TreeTransform.h
@@ -1486,6 +1486,19 @@ public:
                                                StartLoc, LParenLoc, EndLoc);
   }
 
+  /// \brief Build a new OpenMP 'init' clause.
+  ///
+  /// By default, performs semantic analysis to build the new OpenMP clause.
+  /// Subclasses may override this routine to provide different behavior.
+  OMPClause *RebuildOMPInitClause(OpenMPInitClauseKind Kind,
+                                      SourceLocation KindKwLoc,
+                                      SourceLocation StartLoc,
+                                      SourceLocation LParenLoc,
+                                      SourceLocation EndLoc) {
+    return getSema().ActOnOpenMPInitClause(Kind, KindKwLoc,
+                                           StartLoc, LParenLoc, EndLoc);
+  }
+
   /// \brief Build a new OpenMP 'schedule' clause.
   ///
   /// By default, performs semantic analysis to build the new OpenMP clause.
@@ -7715,6 +7728,14 @@ TreeTransform<Derived>::TransformOMPProcBindClause(OMPProcBindClause *C) {
       C->getLParenLoc(), C->getLocEnd());
 }
 
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPInitClause(OMPInitClause *C) {
+  return getDerived().RebuildOMPInitClause(
+      C->getInitKind(), C->getInitKindKwLoc(), C->getLocStart(),
+      C->getLParenLoc(), C->getLocEnd());
+}
+
 template <typename Derived>
 OMPClause *
 TreeTransform<Derived>::TransformOMPScheduleClause(OMPScheduleClause *C) {
diff --git a/lib/Serialization/ASTReaderStmt.cpp b/lib/Serialization/ASTReaderStmt.cpp
index b87710592e9..9778f75251f 100644
--- a/lib/Serialization/ASTReaderStmt.cpp
+++ b/lib/Serialization/ASTReaderStmt.cpp
@@ -1806,6 +1806,9 @@ OMPClause *OMPClauseReader::readClause() {
   case OMPC_proc_bind:
     C = new (Context) OMPProcBindClause();
     break;
+  case OMPC_init:
+    C = new (Context) OMPInitClause();
+    break;
   case OMPC_schedule:
     C = new (Context) OMPScheduleClause();
     break;
@@ -2005,6 +2008,13 @@ void OMPClauseReader::VisitOMPProcBindClause(OMPProcBindClause *C) {
   C->setProcBindKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
 }
 
+void OMPClauseReader::VisitOMPInitClause(OMPInitClause *C) {
+  C->setInitKind(
+       static_cast<OpenMPInitClauseKind>(Record[Idx++]));
+  C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx));
+  C->setInitKindKwLoc(Reader->ReadSourceLocation(Record, Idx));
+}
+
 void OMPClauseReader::VisitOMPScheduleClause(OMPScheduleClause *C) {
   VisitOMPClauseWithPreInit(C);
   C->setScheduleKind(
diff --git a/lib/Serialization/ASTWriterStmt.cpp b/lib/Serialization/ASTWriterStmt.cpp
index 7e766b2daf1..fa2eeeea301 100644
--- a/lib/Serialization/ASTWriterStmt.cpp
+++ b/lib/Serialization/ASTWriterStmt.cpp
@@ -1846,6 +1846,12 @@ void OMPClauseWriter::VisitOMPProcBindClause(OMPProcBindClause *C) {
   Record.AddSourceLocation(C->getProcBindKindKwLoc());
 }
 
+void OMPClauseWriter::VisitOMPInitClause(OMPInitClause *C) {
+  Record.push_back(C->getInitKind());
+  Record.AddSourceLocation(C->getLParenLoc());
+  Record.AddSourceLocation(C->getInitKindKwLoc());
+}
+
 void OMPClauseWriter::VisitOMPScheduleClause(OMPScheduleClause *C) {
   VisitOMPClauseWithPreInit(C);
   Record.push_back(C->getScheduleKind());
diff --git a/tools/libclang/CIndex.cpp b/tools/libclang/CIndex.cpp
index e872c78a515..654fab21298 100644
--- a/tools/libclang/CIndex.cpp
+++ b/tools/libclang/CIndex.cpp
@@ -2090,6 +2090,8 @@ void OMPClauseEnqueue::VisitOMPDefaultClause(const OMPDefaultClause *C) { }
 
 void OMPClauseEnqueue::VisitOMPProcBindClause(const OMPProcBindClause *C) { }
 
+void OMPClauseEnqueue::VisitOMPInitClause(const OMPInitClause *C) { }
+
 void OMPClauseEnqueue::VisitOMPScheduleClause(const OMPScheduleClause *C) {
   VisitOMPClauseWithPreInit(C);
   Visitor->AddStmt(C->getChunkSize());
-- 
GitLab