[clang] [llvm] [Clang][OpenMP] Support for dispatch construct (Sema & Codegen) support (PR #117904)

via llvm-commits llvm-commits at lists.llvm.org
Tue Feb 4 22:44:05 PST 2025


https://github.com/SunilKuravinakop updated https://github.com/llvm/llvm-project/pull/117904

>From 1703aa62cfe35538aedbacb28e907535e838248c Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Fri, 20 Sep 2024 01:41:29 -0500
Subject: [PATCH 01/14] Support for dispatch construct (Sema & Codegen)
 support. Support for clauses depend, novariants & nocontext.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |   3 +
 clang/include/clang/Basic/OpenMPKinds.h       |   6 +
 clang/include/clang/Sema/SemaOpenMP.h         |   7 +
 clang/lib/Basic/OpenMPKinds.cpp               |   5 +
 clang/lib/CodeGen/CGStmt.cpp                  |   2 +-
 clang/lib/CodeGen/CGStmtOpenMP.cpp            |   4 +
 clang/lib/CodeGen/CodeGenFunction.h           |   1 +
 clang/lib/Sema/SemaOpenMP.cpp                 | 301 ++++++++++++++-
 clang/test/OpenMP/dispatch_codegen.cpp        | 359 ++++++++++++++++++
 clang/test/OpenMP/dispatch_unsupported.c      |   7 -
 .../include/llvm/Frontend/OpenMP/OMPContext.h |   6 +
 11 files changed, 687 insertions(+), 14 deletions(-)
 create mode 100644 clang/test/OpenMP/dispatch_codegen.cpp
 delete mode 100644 clang/test/OpenMP/dispatch_unsupported.c

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 8495884dcd058f..81b876f9fd85c5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11774,6 +11774,9 @@ def err_omp_clause_requires_dispatch_construct : Error<
   "'%0' clause requires 'dispatch' context selector">;
 def err_omp_append_args_with_varargs : Error<
   "'append_args' is not allowed with varargs functions">;
+def warn_omp_dispatch_clause_novariants_nocontext : Warning<
+  "only 'novariants' clause is supported when 'novariants' & 'nocontext' clauses occur on the same dispatch construct">,
+  InGroup<SourceUsesOpenMP>;
 def err_openmp_vla_in_task_untied : Error<
   "variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">;
 def warn_omp_unterminated_declare_target : Warning<
diff --git a/clang/include/clang/Basic/OpenMPKinds.h b/clang/include/clang/Basic/OpenMPKinds.h
index 900ad6ca6d66f6..7579fab43dbb19 100644
--- a/clang/include/clang/Basic/OpenMPKinds.h
+++ b/clang/include/clang/Basic/OpenMPKinds.h
@@ -269,6 +269,12 @@ bool isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind);
 /// parallel', otherwise - false.
 bool isOpenMPParallelDirective(OpenMPDirectiveKind DKind);
 
+/// Checks if the specified directive is a dispatch-kind directive.
+/// \param DKind Specified directive.
+/// \return true - the directive is a dispatch-like directive like 'omp
+/// dispatch', otherwise - false.
+bool isOpenMPDispatchDirective(OpenMPDirectiveKind DKind);
+
 /// Checks if the specified directive is a target code offload directive.
 /// \param DKind Specified directive.
 /// \return true - the directive is a target code offload directive like
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index 3d1cc4fab1c10f..80cee9e7583051 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -1462,6 +1462,13 @@ class SemaOpenMP : public SemaBase {
                                            : OMPDeclareVariantScopes.back().TI;
   }
 
+  StmtResult transformDispatchDirective(OpenMPDirectiveKind Kind,
+                                        const DeclarationNameInfo &DirName,
+                                        OpenMPDirectiveKind CancelRegion,
+                                        ArrayRef<OMPClause *> Clauses,
+                                        Stmt *AStmt, SourceLocation StartLoc,
+                                        SourceLocation EndLoc);
+
   /// The current `omp begin/end declare variant` scopes.
   SmallVector<OMPDeclareVariantScope, 4> OMPDeclareVariantScopes;
 
diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 62a13f01481b28..44ee63df46adb5 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -621,6 +621,11 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
          llvm::is_contained(getLeafConstructs(DKind), OMPD_parallel);
 }
 
+bool clang::isOpenMPDispatchDirective(OpenMPDirectiveKind DKind) {
+  return DKind == OMPD_dispatch ||
+         llvm::is_contained(getLeafConstructs(DKind), OMPD_target);
+}
+
 bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) {
   return DKind == OMPD_target ||
          llvm::is_contained(getLeafConstructs(DKind), OMPD_target);
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 698baf853507f4..f3eedb79844378 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -417,7 +417,7 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
     EmitOMPInteropDirective(cast<OMPInteropDirective>(*S));
     break;
   case Stmt::OMPDispatchDirectiveClass:
-    CGM.ErrorUnsupported(S, "OpenMP dispatch directive");
+    EmitOMPDispatchDirective(cast<OMPDispatchDirective>(*S));
     break;
   case Stmt::OMPScopeDirectiveClass:
     EmitOMPScopeDirective(cast<OMPScopeDirective>(*S));
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 6cb37b20b7aeee..f3f2f54b068263 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4452,6 +4452,10 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
   emitMaster(*this, S);
 }
 
+void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) {
+  EmitStmt(S.getAssociatedStmt());
+}
+
 static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
   auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
     Action.Enter(CGF);
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index eaea0d8a08ac06..2e342bc00a94a8 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3830,6 +3830,7 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitOMPSectionDirective(const OMPSectionDirective &S);
   void EmitOMPSingleDirective(const OMPSingleDirective &S);
   void EmitOMPMasterDirective(const OMPMasterDirective &S);
+  void EmitOMPDispatchDirective(const OMPDispatchDirective &S);
   void EmitOMPMaskedDirective(const OMPMaskedDirective &S);
   void EmitOMPCriticalDirective(const OMPCriticalDirective &S);
   void EmitOMPParallelForDirective(const OMPParallelForDirective &S);
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 66ff92f554fc42..28a84a52d8d790 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -4205,6 +4205,8 @@ static void handleDeclareVariantConstructTrait(DSAStackTy *Stack,
   SmallVector<llvm::omp::TraitProperty, 8> Traits;
   if (isOpenMPTargetExecutionDirective(DKind))
     Traits.emplace_back(llvm::omp::TraitProperty::construct_target_target);
+  if (isOpenMPDispatchDirective(DKind))
+    Traits.emplace_back(llvm::omp::TraitProperty::construct_dispatch_dispatch);
   if (isOpenMPTeamsDirective(DKind))
     Traits.emplace_back(llvm::omp::TraitProperty::construct_teams_teams);
   if (isOpenMPParallelDirective(DKind))
@@ -5965,6 +5967,263 @@ static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
   return Checker.teamsLoopCanBeParallelFor();
 }
 
+static Expr *getInitialExprFromCapturedExpr(Expr *Cond) {
+
+  Expr *SubExpr = Cond->IgnoreParenImpCasts();
+
+  if (auto *DeclRef = dyn_cast<DeclRefExpr>(SubExpr)) {
+    if (auto *CapturedExprDecl =
+            dyn_cast<OMPCapturedExprDecl>(DeclRef->getDecl())) {
+
+      // Retrieve the initial expression from the captured expression
+      return CapturedExprDecl->getInit();
+    }
+  }
+  return nullptr;
+}
+
+// Next two functions, cloneAssociatedStmt() &
+// replaceWithNewTraitsOrDirectCall(), are for transforming the call traits.
+// e.g.
+// #pragma omp declare variant(foo_variant_dispatch) match(construct={dispatch})
+// #pragma omp declare variant(foo_variant_allCond) match(user={condition(1)})
+// ..
+//     #pragma omp dispatch nocontext(cond_true)
+//         foo(i, j);
+// is changed to:
+// if (cond_true) {
+//    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
+// } else {
+//   #pragma omp dispatch
+//   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
+// }
+//
+// The next 2 functions, are for:
+// if (cond_true) {
+//   foo(i,j) // with traits: runtime call to foo_variant_allCond(i,j)
+// }
+//
+static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context, Expr *,
+                                              SemaOpenMP *, bool);
+
+static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
+                                      SemaOpenMP *SemaPtr, bool NoContext) {
+  if (CapturedStmt *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
+    CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
+    Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
+    Expr *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
+    Expr *NewCallOrPseudoObjOrBinExpr = replaceWithNewTraitsOrDirectCall(
+        Context, AssocExpr, SemaPtr, NoContext);
+
+    // Copy Current Captured Decl to a New Captured Decl for noting the
+    // Annotation
+    CapturedDecl *NewDecl =
+        CapturedDecl::Create(const_cast<ASTContext &>(Context),
+                             CDecl->getDeclContext(), CDecl->getNumParams());
+    NewDecl->setBody(static_cast<Stmt *>(NewCallOrPseudoObjOrBinExpr));
+    for (unsigned i = 0; i < CDecl->getNumParams(); ++i) {
+      if (i != CDecl->getContextParamPosition())
+        NewDecl->setParam(i, CDecl->getParam(i));
+      else
+        NewDecl->setContextParam(i, CDecl->getContextParam());
+    }
+
+    // Create a New Captured Stmt containing the New Captured Decl
+    SmallVector<CapturedStmt::Capture, 4> Captures;
+    SmallVector<Expr *, 4> CaptureInits;
+    for (auto capture : AssocStmt->captures())
+      Captures.push_back(capture);
+    for (auto capture_init : AssocStmt->capture_inits())
+      CaptureInits.push_back(capture_init);
+    CapturedStmt *NewStmt = CapturedStmt::Create(
+        Context, AssocStmt->getCapturedStmt(),
+        AssocStmt->getCapturedRegionKind(), Captures, CaptureInits, NewDecl,
+        const_cast<RecordDecl *>(AssocStmt->getCapturedRecordDecl()));
+
+    return NewStmt;
+  }
+  return static_cast<Stmt *>(nullptr);
+}
+
+static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
+                                              Expr *AssocExpr,
+                                              SemaOpenMP *SemaPtr,
+                                              bool NoContext) {
+  BinaryOperator *BinaryCopyOpr = nullptr;
+  bool IsBinaryOp = false;
+  Expr *PseudoObjExprOrCall = AssocExpr;
+  if (BinaryOperator *BinOprExpr = dyn_cast<BinaryOperator>(AssocExpr)) {
+    IsBinaryOp = true;
+    BinaryCopyOpr = BinaryOperator::Create(
+        Context, BinOprExpr->getLHS(), BinOprExpr->getRHS(),
+        BinOprExpr->getOpcode(), BinOprExpr->getType(),
+        BinOprExpr->getValueKind(), BinOprExpr->getObjectKind(),
+        BinOprExpr->getOperatorLoc(), FPOptionsOverride());
+    PseudoObjExprOrCall = BinaryCopyOpr->getRHS();
+  }
+
+  Expr *CallWithoutInvariants = PseudoObjExprOrCall;
+  // Change PseudoObjectExpr to a direct call
+  if (PseudoObjectExpr *PseudoObjExpr =
+          dyn_cast<PseudoObjectExpr>(PseudoObjExprOrCall))
+    CallWithoutInvariants = *((PseudoObjExpr->semantics_begin()) - 1);
+
+  Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause
+  if (NoContext) {
+    // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall()
+    CallExpr *CallExprWithinStmt = dyn_cast<CallExpr>(CallWithoutInvariants);
+    int NumArgs = CallExprWithinStmt->getNumArgs();
+    clang::Expr **Args = CallExprWithinStmt->getArgs();
+    // ActOnOpenMPCall() adds traits to a simple function call
+    // e.g. invariant function call traits to "foo(i,j)", if they are present.
+    ExprResult ER = SemaPtr->ActOnOpenMPCall(
+        CallExprWithinStmt, SemaPtr->SemaRef.getCurScope(),
+        CallExprWithinStmt->getBeginLoc(), MultiExprArg(Args, NumArgs),
+        CallExprWithinStmt->getRParenLoc(), static_cast<Expr *>(nullptr));
+    FinalCall = ER.get();
+  }
+
+  if (IsBinaryOp) {
+    BinaryCopyOpr->setRHS(FinalCall);
+    return BinaryCopyOpr;
+  }
+
+  return FinalCall;
+}
+
+static StmtResult combine2Stmts(ASTContext &Context, Stmt *FirstStmt,
+                                Stmt *SecondStmt) {
+
+  llvm::SmallVector<Stmt *, 2> NewCombinedStmtVector;
+  NewCombinedStmtVector.push_back(FirstStmt);
+  NewCombinedStmtVector.push_back(SecondStmt);
+  CompoundStmt *CombinedStmt = CompoundStmt::Create(
+      Context, llvm::ArrayRef<Stmt *>(NewCombinedStmtVector),
+      FPOptionsOverride(), SourceLocation(), SourceLocation());
+  StmtResult FinalStmts(CombinedStmt);
+  return FinalStmts;
+}
+
+template <typename SpecificClause>
+static bool hasClausesOfKind(ArrayRef<OMPClause *> Clauses) {
+  auto ClausesOfKind =
+      OMPExecutableDirective::getClausesOfKind<SpecificClause>(Clauses);
+  return ClausesOfKind.begin() != ClausesOfKind.end();
+}
+
+StmtResult SemaOpenMP::transformDispatchDirective(
+    OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
+    OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
+    Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
+
+  StmtResult RetValue;
+  llvm::SmallVector<OMPClause *, 8> DependVector;
+  for (const OMPDependClause *ConstDependClause :
+       OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)) {
+    OMPDependClause *DependClause =
+        const_cast<OMPDependClause *>(ConstDependClause);
+    DependVector.push_back(DependClause);
+  }
+  llvm::ArrayRef<OMPClause *> DependCArray(DependVector);
+
+  // #pragma omp dispatch depend() is changed to #pragma omp taskwait depend()
+  // This is done by calling ActOnOpenMPExecutableDirective() for the
+  // new taskwait directive.
+  StmtResult DispatchDepend2taskwait =
+      ActOnOpenMPExecutableDirective(OMPD_taskwait, DirName, CancelRegion,
+                                     DependCArray, NULL, StartLoc, EndLoc);
+
+  if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
+
+    if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses)) {
+      Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext);
+    }
+
+    const OMPNovariantsClause *NoVariantsC =
+        OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
+    // #pragma omp dispatch novariants(c2) depend(out: x)
+    // foo();
+    // becomes:
+    // #pragma omp taskwait depend(out: x)
+    // if (c2) {
+    //    foo();
+    // } else {
+    //    #pragma omp dispatch
+    //    foo(); <--- foo() is replaced with foo_variant() in CodeGen
+    // }
+    Expr *Cond = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
+    StmtResult ThenStmt =
+        cloneAssociatedStmt(getASTContext(), AStmt, this, false);
+    SmallVector<OMPClause *, 5> DependClauses;
+    StmtResult ElseStmt = ActOnOpenMPExecutableDirective(
+        Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc);
+    IfStmt *IfElseStmt =
+        IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary,
+                       nullptr, // Init
+                       nullptr, // Condition Var Declaration
+                       Cond,
+                       StartLoc, // Source Location Left Paranthesis
+                       StartLoc, // Source Location Right Paranthesis
+                       ThenStmt.get(), StartLoc, ElseStmt.get());
+    if (hasClausesOfKind<OMPDependClause>(Clauses)) {
+      StmtResult FinalStmts = combine2Stmts(
+          getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt);
+      RetValue = FinalStmts;
+    } else {
+      RetValue = IfElseStmt;
+    }
+  } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
+                 Clauses)) {
+
+    const OMPNocontextClause *NoContextC =
+        OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
+    Expr *Cond = getInitialExprFromCapturedExpr(NoContextC->getCondition());
+    // #pragma omp dispatch depend(out: x) nocontext(c2)
+    // foo();
+    // becomes:
+    // #pragma omp taskwait depend(out: x)
+    // if (c2) {
+    //    foo();
+    // } else {
+    //    #pragma omp dispatch
+    //    foo();
+    // }
+
+    StmtResult ThenStmt =
+        cloneAssociatedStmt(getASTContext(), AStmt, this, true);
+
+    SmallVector<OMPClause *, 5> DependClauses;
+    StmtResult ElseStmt = ActOnOpenMPExecutableDirective(
+        Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc);
+    IfStmt *IfElseStmt =
+        IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary,
+                       nullptr, // Init
+                       nullptr, // Condition Var Declaration
+                       Cond,
+                       StartLoc, // Source Location Left Paranthesis
+                       StartLoc, // Source Location Right Paranthesis
+                       ThenStmt.get(), StartLoc, ElseStmt.get());
+    if (hasClausesOfKind<OMPDependClause>(Clauses)) {
+      StmtResult FinalStmts = combine2Stmts(
+          getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt);
+      RetValue = FinalStmts;
+    } else {
+      RetValue = IfElseStmt;
+    }
+  } else if (hasClausesOfKind<OMPDependClause>(Clauses)) {
+    // Only:
+    // #pragma omp dispatch depend(out: x)
+    // foo();
+    // to
+    // #pragma omp taskwait depend(out: x)
+    // foo();
+    StmtResult FinalStmts =
+        combine2Stmts(getASTContext(), DispatchDepend2taskwait.get(), AStmt);
+    RetValue = FinalStmts;
+  }
+  return RetValue;
+}
+
 StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
     OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
     OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
@@ -5979,6 +6238,20 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
           OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses))
     BindKind = BC->getBindKind();
 
+  if ((Kind == OMPD_dispatch) && (Clauses.size() > 0)) {
+
+    bool UnSupportedClause = false;
+    for (OMPClause *C : Clauses) {
+      if (!((C->getClauseKind() == OMPC_novariants) ||
+            (C->getClauseKind() == OMPC_nocontext) ||
+            (C->getClauseKind() == OMPC_depend)))
+        UnSupportedClause = true;
+    }
+    if (!UnSupportedClause)
+      return transformDispatchDirective(Kind, DirName, CancelRegion, Clauses,
+                                        AStmt, StartLoc, EndLoc);
+  }
+
   if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
     const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
 
@@ -7209,8 +7482,10 @@ ExprResult SemaOpenMP::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
     Exprs.erase(Exprs.begin() + BestIdx);
   } while (!VMIs.empty());
 
-  if (!NewCall.isUsable())
+  if (!NewCall.isUsable()) {
+    fprintf(stdout, "Returning Call, NewCall is not usable\n");
     return Call;
+  }
   return PseudoObjectExpr::Create(getASTContext(), CE, {NewCall.get()}, 0);
 }
 
@@ -10520,11 +10795,22 @@ StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt,
                                      DSAStack->isCancelRegion());
 }
 
+// PseudoObjectExpr is a Trait for dispatch containing the
+// function and its variant. Returning only the function.
+static Expr *RemovePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) {
+  Expr *DirectCallExpr = PseudoObjExprOrDirectCall;
+  if (PseudoObjectExpr *PseudoObjExpr =
+          dyn_cast<PseudoObjectExpr>(PseudoObjExprOrDirectCall))
+    DirectCallExpr = *((PseudoObjExpr->semantics_begin()) - 1);
+  return DirectCallExpr;
+}
+
 static Expr *getDirectCallExpr(Expr *E) {
-  E = E->IgnoreParenCasts()->IgnoreImplicit();
-  if (auto *CE = dyn_cast<CallExpr>(E))
+  Expr *PseudoObjExpr = E->IgnoreParenCasts()->IgnoreImplicit();
+  Expr *DirectCallExpr = RemovePseudoObjectExpr(PseudoObjExpr);
+  if (auto *CE = dyn_cast<CallExpr>(DirectCallExpr))
     if (CE->getDirectCallee())
-      return E;
+      return DirectCallExpr;
   return nullptr;
 }
 
@@ -10556,15 +10842,18 @@ SemaOpenMP::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
     E = E->IgnoreParenCasts()->IgnoreImplicit();
 
     if (auto *BO = dyn_cast<BinaryOperator>(E)) {
-      if (BO->getOpcode() == BO_Assign)
+      if (BO->getOpcode() == BO_Assign) {
         TargetCall = getDirectCallExpr(BO->getRHS());
+      }
     } else {
       if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E))
         if (COCE->getOperator() == OO_Equal)
           TargetCall = getDirectCallExpr(COCE->getArg(1));
-      if (!TargetCall)
+      if (!TargetCall) {
         TargetCall = getDirectCallExpr(E);
+      }
     }
+
     if (!TargetCall) {
       Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call);
       return StmtError();
diff --git a/clang/test/OpenMP/dispatch_codegen.cpp b/clang/test/OpenMP/dispatch_codegen.cpp
new file mode 100644
index 00000000000000..3a50ccbb99873a
--- /dev/null
+++ b/clang/test/OpenMP/dispatch_codegen.cpp
@@ -0,0 +1,359 @@
+// expected-no-diagnostics
+// RUN: %clang_cc1 -DCK1 -verify -fopenmp -x c++ %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-unknown -emit-llvm %s -o - | FileCheck %s
+
+int foo_variant_dispatch(int x, int y) {
+   return x+2;
+}
+
+int foo_variant_allCond(int x, int y) {
+   return x+3;
+}
+
+#pragma omp declare variant(foo_variant_dispatch) match(construct={dispatch})
+#pragma omp declare variant(foo_variant_allCond) match(user={condition(1)})
+int foo(int x, int y) {
+   // Original implementation of foo
+   return x+1;
+}
+
+void checkNoVariants();
+void checkNoContext();
+void checkDepend();
+
+void declareVariant1()
+{
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int y = 0;
+  int output = 0;
+
+  foo(x,y);
+
+  #pragma omp dispatch
+  output = foo(x,y);
+
+  checkNoVariants();
+  checkNoContext();
+  checkDepend();
+}
+
+void checkNoVariants()
+{
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int y = 0;
+  int output = 0;
+
+  #pragma omp dispatch novariants(cond_false)
+  foo(x,y);
+
+  #pragma omp dispatch novariants(cond_true)
+  output = foo(x,y);
+}
+
+void checkNoContext()
+{
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int y = 0;
+  int output = 0;
+
+  #pragma omp dispatch nocontext(cond_false)
+  foo(x,y);
+
+  #pragma omp dispatch nocontext(cond_true)
+  output = foo(x,y);
+
+}
+
+void checkDepend()
+{
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int y = 0;
+  int output = 0;
+
+  #pragma omp dispatch depend(out:x)
+  output = foo(x,y);
+
+  #pragma omp dispatch depend(out:x) depend(out:y)
+  output = foo(x,y);
+
+  #pragma omp dispatch depend(out:x) novariants(cond_false)
+  output = foo(x,y);
+
+  #pragma omp dispatch depend(out:x) nocontext(cond_false)
+  foo(x,y);
+}
+
+int bar_variant(int x) {
+  return x+2;
+}
+
+int bar(int x) {
+  return x+1;
+}
+
+void checkNoContext_withoutVariant();
+void checkNoVariants_withoutVariant();
+
+int without_declareVariant()
+{
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int output = 0;
+
+  bar(x);
+
+  #pragma omp dispatch
+  bar(x);
+
+  checkNoVariants_withoutVariant();
+  checkNoContext_withoutVariant();
+  return 1;
+}
+
+void checkNoVariants_withoutVariant() {
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int output = 0;
+
+  #pragma omp dispatch novariants(cond_true)
+  output = bar(x);
+
+  #pragma omp dispatch novariants(cond_false)
+  bar(x);
+}
+
+void checkNoContext_withoutVariant() {
+  int cond_false = 0, cond_true = 1;
+
+  int x = 0;
+  int output = 0;
+
+  #pragma omp dispatch nocontext(cond_true)
+  output = bar(x);
+
+  #pragma omp dispatch nocontext(cond_false)
+  bar(x);
+}
+
+// CHECK-LABEL: define {{.+}}declareVariant{{.+}}
+// CHECK-LABEL: entry:
+//
+// #pragma omp dispatch
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: call {{.+}}captured_stmt{{.+}}
+// CHECK-NEXT: call {{.+}}checkNoVariants{{.+}}
+// CHECK-NEXT: call {{.+}}checkNoContext{{.+}}
+// CHECK-NEXT: call {{.+}}checkDepend{{.+}}
+// CHECK-NEXT: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: {{.+}}checkNoVariants{{.+}}
+// CHECK-LABEL: entry:
+//  #pragma omp dispatch novariants(cond_false)
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.1{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.2{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+//
+//  #pragma omp dispatch novariants(cond_true)
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.3{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.4{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+//
+// CHECK-LABEL: {{.+}}checkNoContext{{.+}}
+// CHECK-LABEL: entry:
+//
+//  #pragma omp dispatch nocontext(cond_false)
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.5{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.6{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+//
+//  #pragma omp dispatch nocontext(cond_true)
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.7{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.8{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+//
+// CHECK-LABEL: {{.+}}checkDepend{{.+}}
+// CHECK-LABEL: entry:
+//
+//  #pragma omp dispatch depend(out:x)
+// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
+// CHECK: call {{.+}}captured_stmt.9{{.+}}
+//
+//  #pragma omp dispatch depend(out:x) depend(out:y)
+// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
+// CHECK: call {{.+}}captured_stmt.10{{.+}}
+//
+//  #pragma omp dispatch depend(out:x) novariants(cond_false)
+// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.11{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.12{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+//
+//  #pragma omp dispatch depend(out:x) nocontext(cond_false)
+// CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.13{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.14{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.1{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.2{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.3{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.4{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.5{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.6{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.7{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.8{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.9{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.10{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.11{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.12{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.13{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}bar_variant{{.+}}
+// CHECK-LABEL: entry:
+// CHECK: ret{{.+}}
+//
+// CHECK-LABEL: define {{.+}}bar{{.+}}
+// CHECK-LABEL: entry:
+// CHECK: ret{{.+}}
+
+// CHECK-LABEL: define {{.+}}without_declareVariant{{.+}}
+// CHECK-LABEL: entry:
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: call {{.+}}captured_stmt.15{{.+}}
+// CHECK-NEXT: call {{.+}}checkNoVariants_withoutVariant{{.+}}
+// CHECK-NEXT: call {{.+}}checkNoContext_withoutVariant{{.+}}
+// CHECK-NEXT: ret{{.+}}
+//
+//  #pragma omp dispatch
+// CHECK-LABEL: define {{.+}}__captured_stmt.15{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+//
+// CHECK-LABEL: define {{.+}}checkNoVariants_withoutVariant{{.+}}
+// CHECK-LABEL: entry:
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.16{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.17{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.18{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.19{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+// CHECK: ret{{.+}}
+//
+// CHECK-LABEL: define {{.+}}checkNoContext_withoutVariant{{.+}}
+// CHECK-LABEL: entry:
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.20{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.21{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+// CHECK-LABEL: if.then{{.+}}
+// CHECK: call {{.+}}captured_stmt.22{{.+}}
+// CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.23{{.+}}
+// CHECK-LABEL: if.end{{.+}}
+// CHECK: ret{{.+}} 
+//
+// #pragma omp dispatch novariants(cond_true)
+// CHECK-LABEL: define {{.+}}__captured_stmt.16{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+// CHECK-LABEL: define {{.+}}__captured_stmt.17{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+//
+// #pragma omp dispatch novariants(cond_false)
+// CHECK-LABEL: define {{.+}}__captured_stmt.18{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+// CHECK-LABEL: define {{.+}}__captured_stmt.19{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+//
+// #pragma omp dispatch nocontext(cond_true)
+// CHECK-LABEL: define {{.+}}__captured_stmt.20{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+// CHECK-LABEL: define {{.+}}__captured_stmt.21{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+//
+// #pragma omp dispatch nocontext(cond_false)
+// CHECK-LABEL: define {{.+}}__captured_stmt.22{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
+// CHECK-LABEL: define {{.+}}__captured_stmt.23{{.+}}
+// CHECK: call {{.+}}bar{{.+}}
+// CHECK: ret void
diff --git a/clang/test/OpenMP/dispatch_unsupported.c b/clang/test/OpenMP/dispatch_unsupported.c
deleted file mode 100644
index fe7ccfa90a5831..00000000000000
--- a/clang/test/OpenMP/dispatch_unsupported.c
+++ /dev/null
@@ -1,7 +0,0 @@
-// RUN: %clang_cc1 -emit-llvm -fopenmp -disable-llvm-passes %s -o /dev/null -verify=expected
-
-// expected-error at +2 {{cannot compile this OpenMP dispatch directive yet}}
-void a(){
-    #pragma omp dispatch
-    a();
-}
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
index b13b74ceab8651..9ca7bf332f9519 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -141,6 +141,12 @@ struct VariantMatchInfo {
       ISATraits.push_back(RawString);
 
     RequiredTraits.set(unsigned(Property));
+#if 0
+    unsigned int i = 0;
+    for (unsigned Bit : RequiredTraits.set_bits()) {
+	i++;
+    }
+#endif
     if (Set == TraitSet::construct)
       ConstructTraits.push_back(Property);
   }

>From 5ae3ffe4217517c7b442ff64094b2c3e01638063 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Mon, 9 Dec 2024 04:40:16 -0600
Subject: [PATCH 02/14] Taking care of feedback comments from Alexey Bataev. 1)
 Changing comments from // to /// 2) Using STLExtras like
 llvm::is_contained(). 3) Insteading of combining function comments for 2
 functions provided    them separately before the function definitions.

---
 clang/lib/Basic/OpenMPKinds.cpp |  2 +-
 clang/lib/Sema/SemaOpenMP.cpp   | 95 ++++++++++++++++-----------------
 2 files changed, 47 insertions(+), 50 deletions(-)

diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp
index 44ee63df46adb5..45ed0cae2aff26 100644
--- a/clang/lib/Basic/OpenMPKinds.cpp
+++ b/clang/lib/Basic/OpenMPKinds.cpp
@@ -623,7 +623,7 @@ bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) {
 
 bool clang::isOpenMPDispatchDirective(OpenMPDirectiveKind DKind) {
   return DKind == OMPD_dispatch ||
-         llvm::is_contained(getLeafConstructs(DKind), OMPD_target);
+         llvm::is_contained(getLeafConstructs(DKind), OMPD_dispatch);
 }
 
 bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 28a84a52d8d790..affadbf873fb4b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -5982,36 +5982,18 @@ static Expr *getInitialExprFromCapturedExpr(Expr *Cond) {
   return nullptr;
 }
 
-// Next two functions, cloneAssociatedStmt() &
-// replaceWithNewTraitsOrDirectCall(), are for transforming the call traits.
-// e.g.
-// #pragma omp declare variant(foo_variant_dispatch) match(construct={dispatch})
-// #pragma omp declare variant(foo_variant_allCond) match(user={condition(1)})
-// ..
-//     #pragma omp dispatch nocontext(cond_true)
-//         foo(i, j);
-// is changed to:
-// if (cond_true) {
-//    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
-// } else {
-//   #pragma omp dispatch
-//   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
-// }
-//
-// The next 2 functions, are for:
-// if (cond_true) {
-//   foo(i,j) // with traits: runtime call to foo_variant_allCond(i,j)
-// }
-//
 static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context, Expr *,
                                               SemaOpenMP *, bool);
 
+/// cloneAssociatedStmt() function is for cloning the Associated Statement
+/// present with a Directive and then modifying it. By this we avoid modifying
+/// the original Associated Statement.
 static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
                                       SemaOpenMP *SemaPtr, bool NoContext) {
-  if (CapturedStmt *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
+  if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
     CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
     Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
-    Expr *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
+    auto *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
     Expr *NewCallOrPseudoObjOrBinExpr = replaceWithNewTraitsOrDirectCall(
         Context, AssocExpr, SemaPtr, NoContext);
 
@@ -6021,21 +6003,21 @@ static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
         CapturedDecl::Create(const_cast<ASTContext &>(Context),
                              CDecl->getDeclContext(), CDecl->getNumParams());
     NewDecl->setBody(static_cast<Stmt *>(NewCallOrPseudoObjOrBinExpr));
-    for (unsigned i = 0; i < CDecl->getNumParams(); ++i) {
-      if (i != CDecl->getContextParamPosition())
-        NewDecl->setParam(i, CDecl->getParam(i));
+    for (unsigned I : llvm::seq<unsigned>(CDecl->getNumParams())) {
+      if (I != CDecl->getContextParamPosition())
+        NewDecl->setParam(I, CDecl->getParam(I));
       else
-        NewDecl->setContextParam(i, CDecl->getContextParam());
+        NewDecl->setContextParam(I, CDecl->getContextParam());
     }
 
     // Create a New Captured Stmt containing the New Captured Decl
     SmallVector<CapturedStmt::Capture, 4> Captures;
     SmallVector<Expr *, 4> CaptureInits;
-    for (auto capture : AssocStmt->captures())
-      Captures.push_back(capture);
-    for (auto capture_init : AssocStmt->capture_inits())
-      CaptureInits.push_back(capture_init);
-    CapturedStmt *NewStmt = CapturedStmt::Create(
+    for (const CapturedStmt::Capture &Capture : AssocStmt->captures())
+      Captures.push_back(Capture);
+    for (Expr *CaptureInit : AssocStmt->capture_inits())
+      CaptureInits.push_back(CaptureInit);
+    auto *NewStmt = CapturedStmt::Create(
         Context, AssocStmt->getCapturedStmt(),
         AssocStmt->getCapturedRegionKind(), Captures, CaptureInits, NewDecl,
         const_cast<RecordDecl *>(AssocStmt->getCapturedRecordDecl()));
@@ -6045,6 +6027,26 @@ static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
   return static_cast<Stmt *>(nullptr);
 }
 
+/// replaceWithNewTraitsOrDirectCall() is for transforming the call traits.
+/// Call traits associated with a function call are removed and replaced with
+/// a direct call. For clause "nocontext" only, the direct call is then
+/// modified to have call traits for a non-dispatch variant.
+/// For "nocontext" an example is provided below for clear understanding.
+///
+/// #pragma omp declare variant(foo_variant_dispatch)
+/// match(construct={dispatch}) #pragma omp declare variant(foo_variant_allCond)
+/// match(user={condition(1)})
+/// ...
+///     #pragma omp dispatch nocontext(cond_true)
+///         foo(i, j); // with traits: CodeGen call to foo_variant_dispatch(i,j)
+/// dispatch construct is changed to:
+/// if (cond_true) {
+///    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
+/// } else {
+///   #pragma omp dispatch
+///   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
+/// }
+///
 static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
                                               Expr *AssocExpr,
                                               SemaOpenMP *SemaPtr,
@@ -6052,7 +6054,7 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
   BinaryOperator *BinaryCopyOpr = nullptr;
   bool IsBinaryOp = false;
   Expr *PseudoObjExprOrCall = AssocExpr;
-  if (BinaryOperator *BinOprExpr = dyn_cast<BinaryOperator>(AssocExpr)) {
+  if (auto *BinOprExpr = dyn_cast<BinaryOperator>(AssocExpr)) {
     IsBinaryOp = true;
     BinaryCopyOpr = BinaryOperator::Create(
         Context, BinOprExpr->getLHS(), BinOprExpr->getRHS(),
@@ -6064,14 +6066,13 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
 
   Expr *CallWithoutInvariants = PseudoObjExprOrCall;
   // Change PseudoObjectExpr to a direct call
-  if (PseudoObjectExpr *PseudoObjExpr =
-          dyn_cast<PseudoObjectExpr>(PseudoObjExprOrCall))
+  if (auto *PseudoObjExpr = dyn_cast<PseudoObjectExpr>(PseudoObjExprOrCall))
     CallWithoutInvariants = *((PseudoObjExpr->semantics_begin()) - 1);
 
   Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause
   if (NoContext) {
     // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall()
-    CallExpr *CallExprWithinStmt = dyn_cast<CallExpr>(CallWithoutInvariants);
+    auto *CallExprWithinStmt = cast<CallExpr>(CallWithoutInvariants);
     int NumArgs = CallExprWithinStmt->getNumArgs();
     clang::Expr **Args = CallExprWithinStmt->getArgs();
     // ActOnOpenMPCall() adds traits to a simple function call
@@ -6097,7 +6098,7 @@ static StmtResult combine2Stmts(ASTContext &Context, Stmt *FirstStmt,
   llvm::SmallVector<Stmt *, 2> NewCombinedStmtVector;
   NewCombinedStmtVector.push_back(FirstStmt);
   NewCombinedStmtVector.push_back(SecondStmt);
-  CompoundStmt *CombinedStmt = CompoundStmt::Create(
+  auto *CombinedStmt = CompoundStmt::Create(
       Context, llvm::ArrayRef<Stmt *>(NewCombinedStmtVector),
       FPOptionsOverride(), SourceLocation(), SourceLocation());
   StmtResult FinalStmts(CombinedStmt);
@@ -6240,14 +6241,11 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
 
   if ((Kind == OMPD_dispatch) && (Clauses.size() > 0)) {
 
-    bool UnSupportedClause = false;
-    for (OMPClause *C : Clauses) {
-      if (!((C->getClauseKind() == OMPC_novariants) ||
-            (C->getClauseKind() == OMPC_nocontext) ||
-            (C->getClauseKind() == OMPC_depend)))
-        UnSupportedClause = true;
-    }
-    if (!UnSupportedClause)
+    if (llvm::all_of(Clauses, [](OMPClause *C) {
+          return llvm::is_contained(
+              {OMPC_novariants, OMPC_nocontext, OMPC_depend},
+              C->getClauseKind());
+        }))
       return transformDispatchDirective(Kind, DirName, CancelRegion, Clauses,
                                         AStmt, StartLoc, EndLoc);
   }
@@ -7483,7 +7481,6 @@ ExprResult SemaOpenMP::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
   } while (!VMIs.empty());
 
   if (!NewCall.isUsable()) {
-    fprintf(stdout, "Returning Call, NewCall is not usable\n");
     return Call;
   }
   return PseudoObjectExpr::Create(getASTContext(), CE, {NewCall.get()}, 0);
@@ -10795,11 +10792,11 @@ StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt,
                                      DSAStack->isCancelRegion());
 }
 
-// PseudoObjectExpr is a Trait for dispatch containing the
-// function and its variant. Returning only the function.
+/// PseudoObjectExpr is a Trait for dispatch containing the
+/// function and its variant. Returning only the function.
 static Expr *RemovePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) {
   Expr *DirectCallExpr = PseudoObjExprOrDirectCall;
-  if (PseudoObjectExpr *PseudoObjExpr =
+  if (auto *PseudoObjExpr =
           dyn_cast<PseudoObjectExpr>(PseudoObjExprOrDirectCall))
     DirectCallExpr = *((PseudoObjExpr->semantics_begin()) - 1);
   return DirectCallExpr;

>From daf681cc78cc497064b49116df9871a0a1347cdb Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Tue, 10 Dec 2024 12:23:50 -0600
Subject: [PATCH 03/14] Changed the comments for
 replaceWithNewTraitsOrDirectCall().

---
 clang/lib/Sema/SemaOpenMP.cpp | 34 ++++++++++++++++++----------------
 1 file changed, 18 insertions(+), 16 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index affadbf873fb4b..835a92776d0c10 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6031,22 +6031,6 @@ static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
 /// Call traits associated with a function call are removed and replaced with
 /// a direct call. For clause "nocontext" only, the direct call is then
 /// modified to have call traits for a non-dispatch variant.
-/// For "nocontext" an example is provided below for clear understanding.
-///
-/// #pragma omp declare variant(foo_variant_dispatch)
-/// match(construct={dispatch}) #pragma omp declare variant(foo_variant_allCond)
-/// match(user={condition(1)})
-/// ...
-///     #pragma omp dispatch nocontext(cond_true)
-///         foo(i, j); // with traits: CodeGen call to foo_variant_dispatch(i,j)
-/// dispatch construct is changed to:
-/// if (cond_true) {
-///    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
-/// } else {
-///   #pragma omp dispatch
-///   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
-/// }
-///
 static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
                                               Expr *AssocExpr,
                                               SemaOpenMP *SemaPtr,
@@ -6071,6 +6055,24 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
 
   Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause
   if (NoContext) {
+    // example to explain the changes done for "nocontext" clause:
+    //
+    // #pragma omp declare variant(foo_variant_dispatch)
+    // 		 		 match(construct = {dispatch})
+    // #pragma omp declare variant(foo_variant_allCond)
+    // 		 		match(user = {condition(1)})
+    // ...
+    //     #pragma omp dispatch nocontext(cond_true)
+    //         foo(i, j); // with traits: CodeGen call to
+    //         foo_variant_dispatch(i,j)
+    // dispatch construct is changed to:
+    // if (cond_true) {
+    //    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
+    // } else {
+    //   #pragma omp dispatch
+    //   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
+    // }
+
     // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall()
     auto *CallExprWithinStmt = cast<CallExpr>(CallWithoutInvariants);
     int NumArgs = CallExprWithinStmt->getNumArgs();

>From bc3c018fc9715f757a1163b82724a56b9c932098 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Tue, 10 Dec 2024 12:49:39 -0600
Subject: [PATCH 04/14] Removing an unnecessary bracket in if statement in
 ActOnOpenMPCall().

---
 clang/lib/Sema/SemaOpenMP.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 835a92776d0c10..6bc17cea163343 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -7482,9 +7482,8 @@ ExprResult SemaOpenMP::ActOnOpenMPCall(ExprResult Call, Scope *Scope,
     Exprs.erase(Exprs.begin() + BestIdx);
   } while (!VMIs.empty());
 
-  if (!NewCall.isUsable()) {
+  if (!NewCall.isUsable())
     return Call;
-  }
   return PseudoObjectExpr::Create(getASTContext(), CE, {NewCall.get()}, 0);
 }
 

>From b83e0baf49ec540dfaf9f6af1252dd5851472723 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Tue, 10 Dec 2024 14:05:56 -0600
Subject: [PATCH 05/14] Removing unnecessary brackets around if statement.
 Instead of using nullptr for initilizalition StmtResult using an
 uninitialized StmtResult. Unnecessary StmtResult & llvm::ArrayRef variables.

---
 clang/lib/Sema/SemaOpenMP.cpp | 35 +++++++++++++++--------------------
 1 file changed, 15 insertions(+), 20 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 6bc17cea163343..49d0562ea1a41b 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -5990,6 +5990,7 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context, Expr *,
 /// the original Associated Statement.
 static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
                                       SemaOpenMP *SemaPtr, bool NoContext) {
+  StmtResult ResultAssocStmt;
   if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
     CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
     Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
@@ -6022,9 +6023,9 @@ static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
         AssocStmt->getCapturedRegionKind(), Captures, CaptureInits, NewDecl,
         const_cast<RecordDecl *>(AssocStmt->getCapturedRecordDecl()));
 
-    return NewStmt;
+    ResultAssocStmt = NewStmt;
   }
-  return static_cast<Stmt *>(nullptr);
+  return ResultAssocStmt;
 }
 
 /// replaceWithNewTraitsOrDirectCall() is for transforming the call traits.
@@ -6103,8 +6104,7 @@ static StmtResult combine2Stmts(ASTContext &Context, Stmt *FirstStmt,
   auto *CombinedStmt = CompoundStmt::Create(
       Context, llvm::ArrayRef<Stmt *>(NewCombinedStmtVector),
       FPOptionsOverride(), SourceLocation(), SourceLocation());
-  StmtResult FinalStmts(CombinedStmt);
-  return FinalStmts;
+  return CombinedStmt;
 }
 
 template <typename SpecificClause>
@@ -6120,21 +6120,19 @@ StmtResult SemaOpenMP::transformDispatchDirective(
     Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
 
   StmtResult RetValue;
-  llvm::SmallVector<OMPClause *, 8> DependVector;
+  llvm::SmallVector<OMPClause *, 8> DependClauseVector;
   for (const OMPDependClause *ConstDependClause :
        OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)) {
-    OMPDependClause *DependClause =
-        const_cast<OMPDependClause *>(ConstDependClause);
-    DependVector.push_back(DependClause);
+    auto *DependClause = const_cast<OMPDependClause *>(ConstDependClause);
+    DependClauseVector.push_back(DependClause);
   }
-  llvm::ArrayRef<OMPClause *> DependCArray(DependVector);
 
   // #pragma omp dispatch depend() is changed to #pragma omp taskwait depend()
   // This is done by calling ActOnOpenMPExecutableDirective() for the
   // new taskwait directive.
-  StmtResult DispatchDepend2taskwait =
-      ActOnOpenMPExecutableDirective(OMPD_taskwait, DirName, CancelRegion,
-                                     DependCArray, NULL, StartLoc, EndLoc);
+  StmtResult DispatchDepend2taskwait = ActOnOpenMPExecutableDirective(
+      OMPD_taskwait, DirName, CancelRegion, DependClauseVector, NULL, StartLoc,
+      EndLoc);
 
   if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
 
@@ -6241,7 +6239,7 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
           OMPExecutableDirective::getSingleClause<OMPBindClause>(Clauses))
     BindKind = BC->getBindKind();
 
-  if ((Kind == OMPD_dispatch) && (Clauses.size() > 0)) {
+  if ((Kind == OMPD_dispatch) && (!Clauses.empty())) {
 
     if (llvm::all_of(Clauses, [](OMPClause *C) {
           return llvm::is_contained(
@@ -10795,7 +10793,7 @@ StmtResult SemaOpenMP::ActOnOpenMPSectionDirective(Stmt *AStmt,
 
 /// PseudoObjectExpr is a Trait for dispatch containing the
 /// function and its variant. Returning only the function.
-static Expr *RemovePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) {
+static Expr *removePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) {
   Expr *DirectCallExpr = PseudoObjExprOrDirectCall;
   if (auto *PseudoObjExpr =
           dyn_cast<PseudoObjectExpr>(PseudoObjExprOrDirectCall))
@@ -10805,7 +10803,7 @@ static Expr *RemovePseudoObjectExpr(Expr *PseudoObjExprOrDirectCall) {
 
 static Expr *getDirectCallExpr(Expr *E) {
   Expr *PseudoObjExpr = E->IgnoreParenCasts()->IgnoreImplicit();
-  Expr *DirectCallExpr = RemovePseudoObjectExpr(PseudoObjExpr);
+  Expr *DirectCallExpr = removePseudoObjectExpr(PseudoObjExpr);
   if (auto *CE = dyn_cast<CallExpr>(DirectCallExpr))
     if (CE->getDirectCallee())
       return DirectCallExpr;
@@ -10840,18 +10838,15 @@ SemaOpenMP::ActOnOpenMPDispatchDirective(ArrayRef<OMPClause *> Clauses,
     E = E->IgnoreParenCasts()->IgnoreImplicit();
 
     if (auto *BO = dyn_cast<BinaryOperator>(E)) {
-      if (BO->getOpcode() == BO_Assign) {
+      if (BO->getOpcode() == BO_Assign)
         TargetCall = getDirectCallExpr(BO->getRHS());
-      }
     } else {
       if (auto *COCE = dyn_cast<CXXOperatorCallExpr>(E))
         if (COCE->getOperator() == OO_Equal)
           TargetCall = getDirectCallExpr(COCE->getArg(1));
-      if (!TargetCall) {
+      if (!TargetCall)
         TargetCall = getDirectCallExpr(E);
-      }
     }
-
     if (!TargetCall) {
       Diag(E->getBeginLoc(), diag::err_omp_dispatch_statement_call);
       return StmtError();

>From 997fe7c0b140da933f59fb1b9a56b1218e911f4a Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Sun, 15 Dec 2024 12:18:42 -0600
Subject: [PATCH 06/14] 1) Claiming support for "dispatch" construct. 2)
 Changed comments in transformDispatchDirective() in SemaOpenMP.cpp 3) Adding
 checks in clang/test/OpenMP/dispatch_messages.cpp for         a) depend
 clause         b) nocontext, novariants & depend clauses occuring in the same
 line of dispatch construct. 4) Removing debugging statements (kept under #if
 0 and #endif) in OMPContext.h.

---
 clang/docs/OpenMPSupport.rst                  |  2 +
 clang/lib/Sema/SemaOpenMP.cpp                 | 11 +++--
 clang/test/OpenMP/dispatch_messages.cpp       | 42 +++++++++++++++++++
 .../include/llvm/Frontend/OpenMP/OMPContext.h |  6 ---
 4 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst
index 481362dba3f51d..bd591f9981febb 100644
--- a/clang/docs/OpenMPSupport.rst
+++ b/clang/docs/OpenMPSupport.rst
@@ -314,6 +314,8 @@ implementation.
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
 | misc                         | dispatch construct and function variant argument adjustment  | :part:`worked on`        | D99537, D99679                                                        |
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
+| misc                         | dispatch construct   | :part:`worked on`        |  |
++------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
 | misc                         | assumes directives                                           | :part:`worked on`        |                                                                       |
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
 | misc                         | assume directive                                             | :good:`done`             |                                                                       |
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 49d0562ea1a41b..2dbd158e356b4f 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6142,6 +6142,8 @@ StmtResult SemaOpenMP::transformDispatchDirective(
 
     const OMPNovariantsClause *NoVariantsC =
         OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
+    // The following example explains the code transformation in the code
+    //
     // #pragma omp dispatch novariants(c2) depend(out: x)
     // foo();
     // becomes:
@@ -6150,7 +6152,7 @@ StmtResult SemaOpenMP::transformDispatchDirective(
     //    foo();
     // } else {
     //    #pragma omp dispatch
-    //    foo(); <--- foo() is replaced with foo_variant() in CodeGen
+    //    foo();
     // }
     Expr *Cond = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
     StmtResult ThenStmt =
@@ -6179,12 +6181,15 @@ StmtResult SemaOpenMP::transformDispatchDirective(
     const OMPNocontextClause *NoContextC =
         OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
     Expr *Cond = getInitialExprFromCapturedExpr(NoContextC->getCondition());
+    // The following example explains the code transformation in the code
+    //
     // #pragma omp dispatch depend(out: x) nocontext(c2)
     // foo();
     // becomes:
     // #pragma omp taskwait depend(out: x)
     // if (c2) {
-    //    foo();
+    //    foo(); <=== transformation explained clearly in
+    //    	         replaceWithNewTraitsOrDirectCall()
     // } else {
     //    #pragma omp dispatch
     //    foo();
@@ -6215,7 +6220,7 @@ StmtResult SemaOpenMP::transformDispatchDirective(
     // Only:
     // #pragma omp dispatch depend(out: x)
     // foo();
-    // to
+    // becomes:
     // #pragma omp taskwait depend(out: x)
     // foo();
     StmtResult FinalStmts =
diff --git a/clang/test/OpenMP/dispatch_messages.cpp b/clang/test/OpenMP/dispatch_messages.cpp
index 27592e18adfa70..a75bd17a1b98bc 100644
--- a/clang/test/OpenMP/dispatch_messages.cpp
+++ b/clang/test/OpenMP/dispatch_messages.cpp
@@ -64,6 +64,48 @@ void testit_one(int dnum) {
   // expected-error at +1 {{use of undeclared identifier 'x'}}
   #pragma omp dispatch nocontext(x)
   disp_call();
+
+  bool c1 = false;
+  bool c2 = true;
+  int a = 3, b=4;
+  int output;
+ 
+  // expected-error at +1 {{expected '(' after 'depend'}}
+  #pragma omp dispatch depend
+  disp_call();
+
+  // expected-error at +4 {{expected ')'}}
+  // expected-note at +3 {{to match this '('}}
+  // expected-error at +2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}}
+  // expected-warning at +1 {{missing ':' after dependency type}}
+  #pragma omp dispatch depend(
+  disp_call();
+
+  // expected-error at +4 {{expected ')'}}
+  // expected-note at +3 {{to match this '('}}
+  // expected-error at +2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}}
+  // expected-warning at +1 {{missing ':' after dependency type}}
+  #pragma omp dispatch depend(a
+  disp_call();
+
+  // expected-error at +2 {{expected depend modifier(iterator) or 'in', 'out', 'inout', 'mutexinoutset', 'depobj' or 'inoutset' in OpenMP clause 'depend'}}
+  // expected-warning at +1 {{missing ':' after dependency type}}
+  #pragma omp dispatch depend(a)
+  disp_call();
+
+  // expected-error at +1 {{use of undeclared identifier 'z'}}
+  #pragma omp dispatch depend(in:z)
+  disp_call();
+
+  #pragma omp dispatch depend(in:b)
+  output = disp_call();
+
+  #pragma omp dispatch depend(in:b) depend(in:a)
+  output = disp_call();
+
+  // expected-warning at +1 {{only 'novariants' clause is supported when 'novariants' & 'nocontext' clauses occur on the same dispatch construct}}
+  #pragma omp dispatch nocontext(c1) novariants(c2) depend(inout:a)
+  disp_call();
 }
 
 void testit_two() {
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
index 9ca7bf332f9519..b13b74ceab8651 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ b/llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -141,12 +141,6 @@ struct VariantMatchInfo {
       ISATraits.push_back(RawString);
 
     RequiredTraits.set(unsigned(Property));
-#if 0
-    unsigned int i = 0;
-    for (unsigned Bit : RequiredTraits.set_bits()) {
-	i++;
-    }
-#endif
     if (Set == TraitSet::construct)
       ConstructTraits.push_back(Property);
   }

>From 182d02676c85df1bdd917c04a80f1e40110bb31c Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Sun, 15 Dec 2024 12:57:56 -0600
Subject: [PATCH 07/14] Spacing problems for claiming "dispatch construct".

---
 clang/docs/OpenMPSupport.rst | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/docs/OpenMPSupport.rst b/clang/docs/OpenMPSupport.rst
index bd591f9981febb..885a978f07967f 100644
--- a/clang/docs/OpenMPSupport.rst
+++ b/clang/docs/OpenMPSupport.rst
@@ -314,7 +314,7 @@ implementation.
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
 | misc                         | dispatch construct and function variant argument adjustment  | :part:`worked on`        | D99537, D99679                                                        |
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
-| misc                         | dispatch construct   | :part:`worked on`        |  |
+| misc                         | dispatch construct                                           | :part:`worked on`        |                                                                       |
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
 | misc                         | assumes directives                                           | :part:`worked on`        |                                                                       |
 +------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+

>From dca846e2dc4a4a835b4fae977c46e4483219e9fa Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Mon, 16 Dec 2024 02:36:42 -0600
Subject: [PATCH 08/14] Adding support for dispatch construct in Release Notes.

---
 clang/docs/ReleaseNotes.rst | 1 +
 1 file changed, 1 insertion(+)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 9882a1c42d50c4..0bfbd2fcfedd9f 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1098,6 +1098,7 @@ OpenMP Support
 - Added support for 'omp assume' directive.
 - Added support for 'omp scope' directive.
 - Added support for allocator-modifier in 'allocate' clause.
+- Added support for 'omp dispatch' directive.
 
 Improvements
 ^^^^^^^^^^^^

>From 26427bfe51035cacdb2ab19b39baa580b3c169ef Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Wed, 18 Dec 2024 01:12:46 -0600
Subject: [PATCH 09/14] re-wording message in
 warn_omp_dispatch_clause_novariants_nocontext.

---
 clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 81b876f9fd85c5..b7199139e88dd1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11775,7 +11775,7 @@ def err_omp_clause_requires_dispatch_construct : Error<
 def err_omp_append_args_with_varargs : Error<
   "'append_args' is not allowed with varargs functions">;
 def warn_omp_dispatch_clause_novariants_nocontext : Warning<
-  "only 'novariants' clause is supported when 'novariants' & 'nocontext' clauses occur on the same dispatch construct">,
+  "'nocontext' clause is ignored, only 'novariants' clause is applied">,
   InGroup<SourceUsesOpenMP>;
 def err_openmp_vla_in_task_untied : Error<
   "variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">;

>From e379325e93cdef5583089f63d1a52fca9cec0e2b Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Wed, 18 Dec 2024 05:02:58 -0600
Subject: [PATCH 10/14] Changes in expected-warning message for "#pragma omp
 dispatch nocontext(c1) novariants(c2) depend(inout:a)".

---
 clang/test/OpenMP/dispatch_messages.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang/test/OpenMP/dispatch_messages.cpp b/clang/test/OpenMP/dispatch_messages.cpp
index a75bd17a1b98bc..d1435b05224fe1 100644
--- a/clang/test/OpenMP/dispatch_messages.cpp
+++ b/clang/test/OpenMP/dispatch_messages.cpp
@@ -103,7 +103,7 @@ void testit_one(int dnum) {
   #pragma omp dispatch depend(in:b) depend(in:a)
   output = disp_call();
 
-  // expected-warning at +1 {{only 'novariants' clause is supported when 'novariants' & 'nocontext' clauses occur on the same dispatch construct}}
+  // expected-warning at +1 {{'nocontext' clause is ignored, only 'novariants' clause is applied}}
   #pragma omp dispatch nocontext(c1) novariants(c2) depend(inout:a)
   disp_call();
 }

>From bab22e671e9b87acfa31ba7c98fe5a847f56e65f Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe28vega.hpc.amslabs.hpecorp.net>
Date: Thu, 2 Jan 2025 03:29:14 -0600
Subject: [PATCH 11/14] Removing the word CodeGen from comments, which can lead
 to confusion.

---
 clang/lib/Sema/SemaOpenMP.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 2dbd158e356b4f..054b413fb5e5f6 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6064,14 +6064,13 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
     // 		 		match(user = {condition(1)})
     // ...
     //     #pragma omp dispatch nocontext(cond_true)
-    //         foo(i, j); // with traits: CodeGen call to
-    //         foo_variant_dispatch(i,j)
+    //         foo(i,j); // with traits: call to foo_variant_dispatch(i,j)
     // dispatch construct is changed to:
     // if (cond_true) {
-    //    foo(i,j) // with traits: CodeGen call to foo_variant_allCond(i,j)
+    //    foo(i,j) // with traits: call to foo_variant_allCond(i,j)
     // } else {
     //   #pragma omp dispatch
-    //   foo(i,j)  // with traits: CodeGen call to foo_variant_dispatch(i,j)
+    //   foo(i,j)  // with traits: call to foo_variant_dispatch(i,j)
     // }
 
     // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall()

>From 00ac6cfbbd36f1d801510ae8ad62ab35ef8d5748 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe31.hpc.amslabs.hpecorp.net>
Date: Sat, 1 Feb 2025 03:26:44 -0600
Subject: [PATCH 12/14] Moving the helper functions to CodeGen by using
 AnnotateAttr in Sema.

---
 clang/lib/CodeGen/CGStmtOpenMP.cpp  | 103 ++++++++++-
 clang/lib/CodeGen/CodeGenFunction.h |   2 +
 clang/lib/Sema/SemaOpenMP.cpp       | 275 ++++------------------------
 3 files changed, 139 insertions(+), 241 deletions(-)

diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index f3f2f54b068263..3cc7d73373f26c 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4452,8 +4452,100 @@ void CodeGenFunction::EmitOMPMasterDirective(const OMPMasterDirective &S) {
   emitMaster(*this, S);
 }
 
+static Expr *getInitialExprFromCapturedExpr(Expr *Cond) {
+
+  Expr *SubExpr = Cond->IgnoreParenImpCasts();
+
+  if (auto *DeclRef = dyn_cast<DeclRefExpr>(SubExpr)) {
+    if (auto *CapturedExprDecl =
+            dyn_cast<OMPCapturedExprDecl>(DeclRef->getDecl())) {
+
+      // Retrieve the initial expression from the captured expression
+      return CapturedExprDecl->getInit();
+    }
+  }
+  return nullptr;
+}
+
+static Expr *replaceWithNewTraitsOrDirectCall(Stmt *AssocExpr,
+                                              CallExpr *ReplacementFunction) {
+  Expr *FinalCall = ReplacementFunction;
+
+  if (BinaryOperator *BinaryCopyOpr = dyn_cast<BinaryOperator>(AssocExpr)) {
+    BinaryCopyOpr->setRHS(FinalCall);
+    return BinaryCopyOpr;
+  }
+
+  return FinalCall;
+}
+
+static void transformCallInStmt(Stmt *StmtP) {
+  if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
+    CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
+
+    // Access AnnotateAttr
+    CallExpr *NewCallExpr = nullptr;
+    for (const auto *attr : CDecl->attrs()) {
+      if (const auto *annotateAttr = llvm::dyn_cast<clang::AnnotateAttr>(attr);
+          annotateAttr &&
+          annotateAttr->getAnnotation() == "NoContextInvariant") {
+        NewCallExpr = llvm::dyn_cast<CallExpr>(*annotateAttr->args_begin());
+      }
+    }
+
+    Stmt *CallExprStmt = CDecl->getBody();
+    Stmt *NewCallExprStmt =
+        replaceWithNewTraitsOrDirectCall(CallExprStmt, NewCallExpr);
+    CDecl->setBody(NewCallExprStmt);
+  }
+}
+
+static void EmitIfElse(CodeGenFunction *CGF, Expr *Condition,
+                       Stmt *AssociatedStmt) {
+  llvm::Value *CondValue = CGF->EvaluateExprAsBool(Condition);
+  llvm::BasicBlock *ThenBlock = CGF->createBasicBlock("if.then");
+  llvm::BasicBlock *ElseBlock = CGF->createBasicBlock("if.else");
+  llvm::BasicBlock *MergeBlock = CGF->createBasicBlock("if.end");
+
+  CGF->Builder.CreateCondBr(CondValue, ThenBlock, ElseBlock);
+
+  // Emit the else block.
+  Stmt *ElseStmt = AssociatedStmt;
+  CGF->EmitBlock(ElseBlock);
+  CGF->EmitStmt(ElseStmt);
+  CGF->Builder.CreateBr(MergeBlock);
+
+  // Emit the then block.
+  Stmt *ThenStmt = AssociatedStmt;
+  transformCallInStmt(ThenStmt);
+  CGF->EmitBlock(ThenBlock);
+  CGF->EmitStmt(ThenStmt);
+  CGF->Builder.CreateBr(MergeBlock);
+  CGF->EmitBlock(MergeBlock);
+}
+
 void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) {
-  EmitStmt(S.getAssociatedStmt());
+  if (S.hasClausesOfKind<OMPDependClause>()) {
+    EmitOMPDispatchToTaskwaitDirective(S);
+  }
+  ArrayRef<OMPClause *> Clauses = S.clauses();
+  if (S.hasClausesOfKind<OMPNovariantsClause>()) {
+    const OMPNovariantsClause *NoVariantsC =
+        OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
+    Expr *Condition =
+        getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
+    Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
+    EmitIfElse(this, Condition, AssociatedStmt);
+  } else if (S.hasClausesOfKind<OMPNocontextClause>()) {
+    const OMPNocontextClause *NoContextC =
+        OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
+    Expr *Condition =
+        getInitialExprFromCapturedExpr(NoContextC->getCondition());
+    Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
+    EmitIfElse(this, Condition, AssociatedStmt);
+  } else {
+    EmitStmt(S.getAssociatedStmt());
+  }
 }
 
 static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
@@ -5477,6 +5569,15 @@ void CodeGenFunction::EmitOMPBarrierDirective(const OMPBarrierDirective &S) {
   CGM.getOpenMPRuntime().emitBarrierCall(*this, S.getBeginLoc(), OMPD_barrier);
 }
 
+void CodeGenFunction::EmitOMPDispatchToTaskwaitDirective(
+    const OMPDispatchDirective &S) {
+  OMPTaskDataTy Data;
+  // Build list of dependences
+  buildDependences(S, Data);
+  Data.HasNowaitClause = S.hasClausesOfKind<OMPNowaitClause>();
+  CGM.getOpenMPRuntime().emitTaskwaitCall(*this, S.getBeginLoc(), Data);
+}
+
 void CodeGenFunction::EmitOMPTaskwaitDirective(const OMPTaskwaitDirective &S) {
   OMPTaskDataTy Data;
   // Build list of dependences
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 2e342bc00a94a8..c78fa5d88f72b5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -3636,6 +3636,8 @@ class CodeGenFunction : public CodeGenTypeCache {
   void EmitCXXForRangeStmt(const CXXForRangeStmt &S,
                            ArrayRef<const Attr *> Attrs = {});
 
+  void EmitOMPDispatchToTaskwaitDirective(const OMPDispatchDirective &S);
+
   /// Controls insertion of cancellation exit blocks in worksharing constructs.
   class OMPCancelStackRAII {
     CodeGenFunction &CGF;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 054b413fb5e5f6..bc61d7e7386af0 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -5967,86 +5967,16 @@ static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
   return Checker.teamsLoopCanBeParallelFor();
 }
 
-static Expr *getInitialExprFromCapturedExpr(Expr *Cond) {
-
-  Expr *SubExpr = Cond->IgnoreParenImpCasts();
-
-  if (auto *DeclRef = dyn_cast<DeclRefExpr>(SubExpr)) {
-    if (auto *CapturedExprDecl =
-            dyn_cast<OMPCapturedExprDecl>(DeclRef->getDecl())) {
-
-      // Retrieve the initial expression from the captured expression
-      return CapturedExprDecl->getInit();
-    }
-  }
-  return nullptr;
-}
-
-static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context, Expr *,
-                                              SemaOpenMP *, bool);
-
-/// cloneAssociatedStmt() function is for cloning the Associated Statement
-/// present with a Directive and then modifying it. By this we avoid modifying
-/// the original Associated Statement.
-static StmtResult cloneAssociatedStmt(const ASTContext &Context, Stmt *StmtP,
-                                      SemaOpenMP *SemaPtr, bool NoContext) {
-  StmtResult ResultAssocStmt;
-  if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
-    CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
-    Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
-    auto *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
-    Expr *NewCallOrPseudoObjOrBinExpr = replaceWithNewTraitsOrDirectCall(
-        Context, AssocExpr, SemaPtr, NoContext);
-
-    // Copy Current Captured Decl to a New Captured Decl for noting the
-    // Annotation
-    CapturedDecl *NewDecl =
-        CapturedDecl::Create(const_cast<ASTContext &>(Context),
-                             CDecl->getDeclContext(), CDecl->getNumParams());
-    NewDecl->setBody(static_cast<Stmt *>(NewCallOrPseudoObjOrBinExpr));
-    for (unsigned I : llvm::seq<unsigned>(CDecl->getNumParams())) {
-      if (I != CDecl->getContextParamPosition())
-        NewDecl->setParam(I, CDecl->getParam(I));
-      else
-        NewDecl->setContextParam(I, CDecl->getContextParam());
-    }
-
-    // Create a New Captured Stmt containing the New Captured Decl
-    SmallVector<CapturedStmt::Capture, 4> Captures;
-    SmallVector<Expr *, 4> CaptureInits;
-    for (const CapturedStmt::Capture &Capture : AssocStmt->captures())
-      Captures.push_back(Capture);
-    for (Expr *CaptureInit : AssocStmt->capture_inits())
-      CaptureInits.push_back(CaptureInit);
-    auto *NewStmt = CapturedStmt::Create(
-        Context, AssocStmt->getCapturedStmt(),
-        AssocStmt->getCapturedRegionKind(), Captures, CaptureInits, NewDecl,
-        const_cast<RecordDecl *>(AssocStmt->getCapturedRecordDecl()));
-
-    ResultAssocStmt = NewStmt;
-  }
-  return ResultAssocStmt;
-}
-
-/// replaceWithNewTraitsOrDirectCall() is for transforming the call traits.
+/// getNewTraitsOrDirectCall() is for transforming the call traits.
 /// Call traits associated with a function call are removed and replaced with
 /// a direct call. For clause "nocontext" only, the direct call is then
-/// modified to have call traits for a non-dispatch variant.
-static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
-                                              Expr *AssocExpr,
-                                              SemaOpenMP *SemaPtr,
-                                              bool NoContext) {
-  BinaryOperator *BinaryCopyOpr = nullptr;
-  bool IsBinaryOp = false;
+/// modified to have call traits for a non-dispatch (directive) variant.
+static Expr *getNewTraitsOrDirectCall(const ASTContext &Context,
+                                      Expr *AssocExpr, SemaOpenMP *SemaPtr,
+                                      bool NoContext) {
   Expr *PseudoObjExprOrCall = AssocExpr;
   if (auto *BinOprExpr = dyn_cast<BinaryOperator>(AssocExpr)) {
-    IsBinaryOp = true;
-    BinaryCopyOpr = BinaryOperator::Create(
-        Context, BinOprExpr->getLHS(), BinOprExpr->getRHS(),
-        BinOprExpr->getOpcode(), BinOprExpr->getType(),
-        BinOprExpr->getValueKind(), BinOprExpr->getObjectKind(),
-        BinOprExpr->getOperatorLoc(), FPOptionsOverride());
-    PseudoObjExprOrCall = BinaryCopyOpr->getRHS();
+    PseudoObjExprOrCall = BinOprExpr->getRHS();
   }
 
   Expr *CallWithoutInvariants = PseudoObjExprOrCall;
@@ -6056,24 +5986,6 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
 
   Expr *FinalCall = CallWithoutInvariants; // For noinvariants clause
   if (NoContext) {
-    // example to explain the changes done for "nocontext" clause:
-    //
-    // #pragma omp declare variant(foo_variant_dispatch)
-    // 		 		 match(construct = {dispatch})
-    // #pragma omp declare variant(foo_variant_allCond)
-    // 		 		match(user = {condition(1)})
-    // ...
-    //     #pragma omp dispatch nocontext(cond_true)
-    //         foo(i,j); // with traits: call to foo_variant_dispatch(i,j)
-    // dispatch construct is changed to:
-    // if (cond_true) {
-    //    foo(i,j) // with traits: call to foo_variant_allCond(i,j)
-    // } else {
-    //   #pragma omp dispatch
-    //   foo(i,j)  // with traits: call to foo_variant_dispatch(i,j)
-    // }
-
-    // Convert StmtResult to a CallExpr before calling ActOnOpenMPCall()
     auto *CallExprWithinStmt = cast<CallExpr>(CallWithoutInvariants);
     int NumArgs = CallExprWithinStmt->getNumArgs();
     clang::Expr **Args = CallExprWithinStmt->getArgs();
@@ -6084,149 +5996,34 @@ static Expr *replaceWithNewTraitsOrDirectCall(const ASTContext &Context,
         CallExprWithinStmt->getBeginLoc(), MultiExprArg(Args, NumArgs),
         CallExprWithinStmt->getRParenLoc(), static_cast<Expr *>(nullptr));
     FinalCall = ER.get();
+    if (auto *PseudoObjExpr = dyn_cast<PseudoObjectExpr>(ER.get()))
+      FinalCall = *((PseudoObjExpr->semantics_begin()));
   }
-
-  if (IsBinaryOp) {
-    BinaryCopyOpr->setRHS(FinalCall);
-    return BinaryCopyOpr;
-  }
-
   return FinalCall;
 }
 
-static StmtResult combine2Stmts(ASTContext &Context, Stmt *FirstStmt,
-                                Stmt *SecondStmt) {
-
-  llvm::SmallVector<Stmt *, 2> NewCombinedStmtVector;
-  NewCombinedStmtVector.push_back(FirstStmt);
-  NewCombinedStmtVector.push_back(SecondStmt);
-  auto *CombinedStmt = CompoundStmt::Create(
-      Context, llvm::ArrayRef<Stmt *>(NewCombinedStmtVector),
-      FPOptionsOverride(), SourceLocation(), SourceLocation());
-  return CombinedStmt;
-}
-
-template <typename SpecificClause>
-static bool hasClausesOfKind(ArrayRef<OMPClause *> Clauses) {
-  auto ClausesOfKind =
-      OMPExecutableDirective::getClausesOfKind<SpecificClause>(Clauses);
-  return ClausesOfKind.begin() != ClausesOfKind.end();
-}
-
-StmtResult SemaOpenMP::transformDispatchDirective(
-    OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
-    OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
-    Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) {
-
-  StmtResult RetValue;
-  llvm::SmallVector<OMPClause *, 8> DependClauseVector;
-  for (const OMPDependClause *ConstDependClause :
-       OMPExecutableDirective::getClausesOfKind<OMPDependClause>(Clauses)) {
-    auto *DependClause = const_cast<OMPDependClause *>(ConstDependClause);
-    DependClauseVector.push_back(DependClause);
-  }
-
-  // #pragma omp dispatch depend() is changed to #pragma omp taskwait depend()
-  // This is done by calling ActOnOpenMPExecutableDirective() for the
-  // new taskwait directive.
-  StmtResult DispatchDepend2taskwait = ActOnOpenMPExecutableDirective(
-      OMPD_taskwait, DirName, CancelRegion, DependClauseVector, NULL, StartLoc,
-      EndLoc);
-
-  if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
-
-    if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses)) {
-      Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext);
-    }
-
-    const OMPNovariantsClause *NoVariantsC =
-        OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
-    // The following example explains the code transformation in the code
-    //
-    // #pragma omp dispatch novariants(c2) depend(out: x)
-    // foo();
-    // becomes:
-    // #pragma omp taskwait depend(out: x)
-    // if (c2) {
-    //    foo();
-    // } else {
-    //    #pragma omp dispatch
-    //    foo();
-    // }
-    Expr *Cond = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
-    StmtResult ThenStmt =
-        cloneAssociatedStmt(getASTContext(), AStmt, this, false);
-    SmallVector<OMPClause *, 5> DependClauses;
-    StmtResult ElseStmt = ActOnOpenMPExecutableDirective(
-        Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc);
-    IfStmt *IfElseStmt =
-        IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary,
-                       nullptr, // Init
-                       nullptr, // Condition Var Declaration
-                       Cond,
-                       StartLoc, // Source Location Left Paranthesis
-                       StartLoc, // Source Location Right Paranthesis
-                       ThenStmt.get(), StartLoc, ElseStmt.get());
-    if (hasClausesOfKind<OMPDependClause>(Clauses)) {
-      StmtResult FinalStmts = combine2Stmts(
-          getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt);
-      RetValue = FinalStmts;
-    } else {
-      RetValue = IfElseStmt;
-    }
-  } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
-                 Clauses)) {
-
-    const OMPNocontextClause *NoContextC =
-        OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
-    Expr *Cond = getInitialExprFromCapturedExpr(NoContextC->getCondition());
-    // The following example explains the code transformation in the code
-    //
-    // #pragma omp dispatch depend(out: x) nocontext(c2)
-    // foo();
-    // becomes:
-    // #pragma omp taskwait depend(out: x)
-    // if (c2) {
-    //    foo(); <=== transformation explained clearly in
-    //    	         replaceWithNewTraitsOrDirectCall()
-    // } else {
-    //    #pragma omp dispatch
-    //    foo();
-    // }
-
-    StmtResult ThenStmt =
-        cloneAssociatedStmt(getASTContext(), AStmt, this, true);
-
-    SmallVector<OMPClause *, 5> DependClauses;
-    StmtResult ElseStmt = ActOnOpenMPExecutableDirective(
-        Kind, DirName, CancelRegion, DependClauses, AStmt, StartLoc, EndLoc);
-    IfStmt *IfElseStmt =
-        IfStmt::Create(getASTContext(), StartLoc, IfStatementKind::Ordinary,
-                       nullptr, // Init
-                       nullptr, // Condition Var Declaration
-                       Cond,
-                       StartLoc, // Source Location Left Paranthesis
-                       StartLoc, // Source Location Right Paranthesis
-                       ThenStmt.get(), StartLoc, ElseStmt.get());
-    if (hasClausesOfKind<OMPDependClause>(Clauses)) {
-      StmtResult FinalStmts = combine2Stmts(
-          getASTContext(), DispatchDepend2taskwait.get(), IfElseStmt);
-      RetValue = FinalStmts;
-    } else {
-      RetValue = IfElseStmt;
-    }
-  } else if (hasClausesOfKind<OMPDependClause>(Clauses)) {
-    // Only:
-    // #pragma omp dispatch depend(out: x)
-    // foo();
-    // becomes:
-    // #pragma omp taskwait depend(out: x)
-    // foo();
-    StmtResult FinalStmts =
-        combine2Stmts(getASTContext(), DispatchDepend2taskwait.get(), AStmt);
-    RetValue = FinalStmts;
+/// annotateAStmt() function is used by ActOnOpenMPExecutableDirective()
+/// for the dispatch directive (nocontext or invariant clauses) dispatch
+/// directive. An annotation "NoContextInvariant" is added to the Captured Decl
+/// in the Associated Stmt. This annotation contains either a call to the
+/// function, not to any of its variants (for invariant clause) or a variant
+/// function (for nocontext clause).
+static void annotateAStmt(const ASTContext &Context, Stmt *StmtP,
+                          SemaOpenMP *SemaPtr, bool NoContext) {
+  StmtResult ResultAssocStmt;
+  if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
+    CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
+    Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
+    auto *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
+    Expr *NewCallExpr =
+        getNewTraitsOrDirectCall(Context, AssocExpr, SemaPtr, NoContext);
+    // Annotate "NoContextInvariant" to CDecl of the AssocStmt
+    llvm::SmallVector<Expr *, 4> Args;
+    Args.push_back(NewCallExpr);
+    CDecl->addAttr(AnnotateAttr::CreateImplicit(
+        const_cast<ASTContext &>(Context), "NoContextInvariant", Args.data(),
+        Args.size()));
   }
-  return RetValue;
 }
 
 StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
@@ -6244,14 +6041,12 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
     BindKind = BC->getBindKind();
 
   if ((Kind == OMPD_dispatch) && (!Clauses.empty())) {
-
-    if (llvm::all_of(Clauses, [](OMPClause *C) {
-          return llvm::is_contained(
-              {OMPC_novariants, OMPC_nocontext, OMPC_depend},
-              C->getClauseKind());
-        }))
-      return transformDispatchDirective(Kind, DirName, CancelRegion, Clauses,
-                                        AStmt, StartLoc, EndLoc);
+    if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
+      annotateAStmt(getASTContext(), AStmt, this, false);
+    } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
+                   Clauses)) {
+      annotateAStmt(getASTContext(), AStmt, this, true);
+    }
   }
 
   if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {

>From ff2f370b3bfcba325c3e0cfa6a78a9151b013eba Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe31.hpc.amslabs.hpecorp.net>
Date: Tue, 4 Feb 2025 00:48:04 -0600
Subject: [PATCH 13/14] Changing the commit message from:   'nocontext' clause
 is ignored, only 'novariants' clause is applied to   first occuring clause
 among 'nocontext' or 'novariants' is applied This is being done because of
 usage of llvm::any_of & llvm::is_contained instead of if statements.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/lib/CodeGen/CGStmtOpenMP.cpp            | 28 ++++----
 clang/lib/Sema/SemaOpenMP.cpp                 | 19 ++++--
 clang/test/OpenMP/dispatch_ast_print.cpp      |  1 -
 clang/test/OpenMP/dispatch_codegen.cpp        | 64 +++++++++----------
 clang/test/OpenMP/dispatch_messages.cpp       |  2 +-
 6 files changed, 63 insertions(+), 53 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index b7199139e88dd1..6d2f94dccd425e 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11775,7 +11775,7 @@ def err_omp_clause_requires_dispatch_construct : Error<
 def err_omp_append_args_with_varargs : Error<
   "'append_args' is not allowed with varargs functions">;
 def warn_omp_dispatch_clause_novariants_nocontext : Warning<
-  "'nocontext' clause is ignored, only 'novariants' clause is applied">,
+  "first occuring clause among 'nocontext' or 'novariants' is applied">,
   InGroup<SourceUsesOpenMP>;
 def err_openmp_vla_in_task_untied : Error<
   "variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 3cc7d73373f26c..0724b7cf0f62a3 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4529,18 +4529,22 @@ void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) {
     EmitOMPDispatchToTaskwaitDirective(S);
   }
   ArrayRef<OMPClause *> Clauses = S.clauses();
-  if (S.hasClausesOfKind<OMPNovariantsClause>()) {
-    const OMPNovariantsClause *NoVariantsC =
-        OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
-    Expr *Condition =
-        getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
-    Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
-    EmitIfElse(this, Condition, AssociatedStmt);
-  } else if (S.hasClausesOfKind<OMPNocontextClause>()) {
-    const OMPNocontextClause *NoContextC =
-        OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
-    Expr *Condition =
-        getInitialExprFromCapturedExpr(NoContextC->getCondition());
+  bool IsClauseNoContext = false;
+  if (llvm::any_of(Clauses, [&IsClauseNoContext](OMPClause *C) {
+        IsClauseNoContext = (C->getClauseKind() == OMPC_nocontext);
+        return llvm::is_contained({OMPC_novariants, OMPC_nocontext},
+                                  C->getClauseKind());
+      })) {
+    Expr *Condition = nullptr;
+    if (IsClauseNoContext) {
+      const OMPNocontextClause *NoContextC =
+          OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
+      Condition = getInitialExprFromCapturedExpr(NoContextC->getCondition());
+    } else {
+      const OMPNovariantsClause *NoVariantsC =
+          OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
+      Condition = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
+    }
     Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
     EmitIfElse(this, Condition, AssociatedStmt);
   } else {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index bc61d7e7386af0..69b6c0fd111bf7 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6041,14 +6041,21 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
     BindKind = BC->getBindKind();
 
   if ((Kind == OMPD_dispatch) && (!Clauses.empty())) {
-    if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
-      annotateAStmt(getASTContext(), AStmt, this, false);
-    } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
-                   Clauses)) {
-      annotateAStmt(getASTContext(), AStmt, this, true);
+    bool IsClauseNoContext = false;
+    if (llvm::any_of(Clauses, [&IsClauseNoContext](OMPClause *C) {
+          IsClauseNoContext = (C->getClauseKind() == OMPC_nocontext);
+          return llvm::is_contained({OMPC_novariants, OMPC_nocontext},
+                                    C->getClauseKind());
+        })) {
+      if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
+              Clauses) &&
+          OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(
+              Clauses)) {
+        Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext);
+      }
+      annotateAStmt(getASTContext(), AStmt, this, IsClauseNoContext);
     }
   }
-
   if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
     const OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective();
 
diff --git a/clang/test/OpenMP/dispatch_ast_print.cpp b/clang/test/OpenMP/dispatch_ast_print.cpp
index 6065f4f6e68ca9..54ba5c19df51c7 100644
--- a/clang/test/OpenMP/dispatch_ast_print.cpp
+++ b/clang/test/OpenMP/dispatch_ast_print.cpp
@@ -4,7 +4,6 @@
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp \
 // RUN:   -fsyntax-only -verify %s
 
-// expected-no-diagnostics
 
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp \
 // RUN:   -ast-print %s | FileCheck %s --check-prefix=PRINT
diff --git a/clang/test/OpenMP/dispatch_codegen.cpp b/clang/test/OpenMP/dispatch_codegen.cpp
index 3a50ccbb99873a..c3be66c6bbc7d9 100644
--- a/clang/test/OpenMP/dispatch_codegen.cpp
+++ b/clang/test/OpenMP/dispatch_codegen.cpp
@@ -163,16 +163,16 @@ void checkNoContext_withoutVariant() {
 // CHECK-LABEL: {{.+}}checkNoVariants{{.+}}
 // CHECK-LABEL: entry:
 //  #pragma omp dispatch novariants(cond_false)
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.1{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.1{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.2{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
 //  #pragma omp dispatch novariants(cond_true)
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.3{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.3{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.4{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
@@ -180,16 +180,16 @@ void checkNoContext_withoutVariant() {
 // CHECK-LABEL: entry:
 //
 //  #pragma omp dispatch nocontext(cond_false)
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.5{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.5{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.6{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
 //  #pragma omp dispatch nocontext(cond_true)
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.7{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.7{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.8{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
@@ -206,51 +206,51 @@ void checkNoContext_withoutVariant() {
 //
 //  #pragma omp dispatch depend(out:x) novariants(cond_false)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.11{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.11{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.12{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
 //  #pragma omp dispatch depend(out:x) nocontext(cond_false)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.13{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.13{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.14{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.1{{.+}}
-// CHECK: call {{.+}}foo{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.2{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.3{{.+}}
-// CHECK: call {{.+}}foo{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.4{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.5{{.+}}
-// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.6{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.7{{.+}}
-// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.8{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.9{{.+}}
@@ -262,19 +262,19 @@ void checkNoContext_withoutVariant() {
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.11{{.+}}
-// CHECK: call {{.+}}foo{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.12{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.13{{.+}}
-// CHECK: call {{.+}}foo_variant_allCond{{.+}}
+// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo_variant_allCond{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}bar_variant{{.+}}
@@ -300,28 +300,28 @@ void checkNoContext_withoutVariant() {
 //
 // CHECK-LABEL: define {{.+}}checkNoVariants_withoutVariant{{.+}}
 // CHECK-LABEL: entry:
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.16{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.16{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.17{{.+}}
 // CHECK-LABEL: if.end{{.+}}
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.18{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.18{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.19{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret{{.+}}
 //
 // CHECK-LABEL: define {{.+}}checkNoContext_withoutVariant{{.+}}
 // CHECK-LABEL: entry:
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.20{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.20{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.21{{.+}}
 // CHECK-LABEL: if.end{{.+}}
-// CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.22{{.+}}
 // CHECK-LABEL: if.else{{.+}}
+// CHECK: call {{.+}}captured_stmt.22{{.+}}
+// CHECK-LABEL: if.then{{.+}}
 // CHECK: call {{.+}}captured_stmt.23{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret{{.+}} 
diff --git a/clang/test/OpenMP/dispatch_messages.cpp b/clang/test/OpenMP/dispatch_messages.cpp
index d1435b05224fe1..41944c8516baf8 100644
--- a/clang/test/OpenMP/dispatch_messages.cpp
+++ b/clang/test/OpenMP/dispatch_messages.cpp
@@ -103,7 +103,7 @@ void testit_one(int dnum) {
   #pragma omp dispatch depend(in:b) depend(in:a)
   output = disp_call();
 
-  // expected-warning at +1 {{'nocontext' clause is ignored, only 'novariants' clause is applied}}
+  // expected-warning at +1 {{first occuring clause among 'nocontext' or 'novariants' is applied}}
   #pragma omp dispatch nocontext(c1) novariants(c2) depend(inout:a)
   disp_call();
 }

>From de5b7cc5654229e1e2521b1a171472dbdfb08e53 Mon Sep 17 00:00:00 2001
From: Sunil Kuravinakop <kuravina at pe31.hpc.amslabs.hpecorp.net>
Date: Tue, 4 Feb 2025 13:11:25 -0600
Subject: [PATCH 14/14] All clang/test/OpenMP/dispatch_*.cpp tests pass with
 the changes in this commit.

---
 .../clang/Basic/DiagnosticSemaKinds.td        |  2 +-
 clang/include/clang/Sema/SemaOpenMP.h         |  9 +--
 clang/lib/CodeGen/CGStmtOpenMP.cpp            | 43 +++++++-------
 clang/lib/Sema/SemaOpenMP.cpp                 | 42 ++++++++------
 clang/test/OpenMP/dispatch_ast_print.cpp      |  1 +
 clang/test/OpenMP/dispatch_codegen.cpp        | 56 ++++++++-----------
 clang/test/OpenMP/dispatch_messages.cpp       |  2 +-
 7 files changed, 75 insertions(+), 80 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 6d2f94dccd425e..b7199139e88dd1 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -11775,7 +11775,7 @@ def err_omp_clause_requires_dispatch_construct : Error<
 def err_omp_append_args_with_varargs : Error<
   "'append_args' is not allowed with varargs functions">;
 def warn_omp_dispatch_clause_novariants_nocontext : Warning<
-  "first occuring clause among 'nocontext' or 'novariants' is applied">,
+  "'nocontext' clause is ignored, only 'novariants' clause is applied">,
   InGroup<SourceUsesOpenMP>;
 def err_openmp_vla_in_task_untied : Error<
   "variable length arrays are not supported in OpenMP tasking regions with 'untied' clause">;
diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h
index 80cee9e7583051..6eae0021a32117 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -1462,12 +1462,9 @@ class SemaOpenMP : public SemaBase {
                                            : OMPDeclareVariantScopes.back().TI;
   }
 
-  StmtResult transformDispatchDirective(OpenMPDirectiveKind Kind,
-                                        const DeclarationNameInfo &DirName,
-                                        OpenMPDirectiveKind CancelRegion,
-                                        ArrayRef<OMPClause *> Clauses,
-                                        Stmt *AStmt, SourceLocation StartLoc,
-                                        SourceLocation EndLoc);
+  void annotateAStmt(const ASTContext &Context, Stmt *StmtP,
+                     SemaOpenMP *SemaPtr, ArrayRef<OMPClause *> &Clauses,
+                     SourceLocation StartLoc);
 
   /// The current `omp begin/end declare variant` scopes.
   SmallVector<OMPDeclareVariantScope, 4> OMPDeclareVariantScopes;
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 0724b7cf0f62a3..9ac5f5841bbfe5 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -4525,31 +4525,30 @@ static void EmitIfElse(CodeGenFunction *CGF, Expr *Condition,
 }
 
 void CodeGenFunction::EmitOMPDispatchDirective(const OMPDispatchDirective &S) {
-  if (S.hasClausesOfKind<OMPDependClause>()) {
-    EmitOMPDispatchToTaskwaitDirective(S);
-  }
   ArrayRef<OMPClause *> Clauses = S.clauses();
-  bool IsClauseNoContext = false;
-  if (llvm::any_of(Clauses, [&IsClauseNoContext](OMPClause *C) {
-        IsClauseNoContext = (C->getClauseKind() == OMPC_nocontext);
-        return llvm::is_contained({OMPC_novariants, OMPC_nocontext},
-                                  C->getClauseKind());
-      })) {
-    Expr *Condition = nullptr;
-    if (IsClauseNoContext) {
-      const OMPNocontextClause *NoContextC =
-          OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses);
-      Condition = getInitialExprFromCapturedExpr(NoContextC->getCondition());
-    } else {
-      const OMPNovariantsClause *NoVariantsC =
-          OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses);
-      Condition = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
+  if (!Clauses.empty()) {
+    if (S.hasClausesOfKind<OMPDependClause>())
+      EmitOMPDispatchToTaskwaitDirective(S);
+
+    if (S.hasClausesOfKind<OMPNovariantsClause>() ||
+        S.hasClausesOfKind<OMPNocontextClause>()) {
+      Expr *Condition = nullptr;
+      if (const OMPNovariantsClause *NoVariantsC =
+              OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(
+                  Clauses)) {
+        Condition = getInitialExprFromCapturedExpr(NoVariantsC->getCondition());
+      } else {
+        const OMPNocontextClause *NoContextC =
+            OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
+                Clauses);
+        Condition = getInitialExprFromCapturedExpr(NoContextC->getCondition());
+      }
+      /* OMPC_novariants or OMPC_nocontext present */
+      Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
+      EmitIfElse(this, Condition, AssociatedStmt);
     }
-    Stmt *AssociatedStmt = const_cast<Stmt *>(S.getAssociatedStmt());
-    EmitIfElse(this, Condition, AssociatedStmt);
-  } else {
+  } else
     EmitStmt(S.getAssociatedStmt());
-  }
 }
 
 static void emitMasked(CodeGenFunction &CGF, const OMPExecutableDirective &S) {
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 69b6c0fd111bf7..5fb4a0cdf6aab3 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -6003,18 +6003,29 @@ static Expr *getNewTraitsOrDirectCall(const ASTContext &Context,
 }
 
 /// annotateAStmt() function is used by ActOnOpenMPExecutableDirective()
-/// for the dispatch directive (nocontext or invariant clauses) dispatch
-/// directive. An annotation "NoContextInvariant" is added to the Captured Decl
+/// for the dispatch directive (nocontext or invariant clauses).
+/// An annotation "NoContextInvariant" is added to the Captured Decl
 /// in the Associated Stmt. This annotation contains either a call to the
 /// function, not to any of its variants (for invariant clause) or a variant
 /// function (for nocontext clause).
-static void annotateAStmt(const ASTContext &Context, Stmt *StmtP,
-                          SemaOpenMP *SemaPtr, bool NoContext) {
-  StmtResult ResultAssocStmt;
+void SemaOpenMP::annotateAStmt(const ASTContext &Context, Stmt *StmtP,
+                               SemaOpenMP *SemaPtr,
+                               ArrayRef<OMPClause *> &Clauses,
+                               SourceLocation StartLoc) {
   if (auto *AssocStmt = dyn_cast<CapturedStmt>(StmtP)) {
     CapturedDecl *CDecl = AssocStmt->getCapturedDecl();
     Stmt *AssocExprStmt = AssocStmt->getCapturedStmt();
     auto *AssocExpr = dyn_cast<Expr>(AssocExprStmt);
+    bool NoContext = false;
+
+    if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(Clauses)) {
+
+      if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses))
+        Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext);
+    } else if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
+                   Clauses))
+      NoContext = true;
+
     Expr *NewCallExpr =
         getNewTraitsOrDirectCall(Context, AssocExpr, SemaPtr, NoContext);
     // Annotate "NoContextInvariant" to CDecl of the AssocStmt
@@ -6041,19 +6052,16 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective(
     BindKind = BC->getBindKind();
 
   if ((Kind == OMPD_dispatch) && (!Clauses.empty())) {
-    bool IsClauseNoContext = false;
-    if (llvm::any_of(Clauses, [&IsClauseNoContext](OMPClause *C) {
-          IsClauseNoContext = (C->getClauseKind() == OMPC_nocontext);
-          return llvm::is_contained({OMPC_novariants, OMPC_nocontext},
-                                    C->getClauseKind());
+
+    if (llvm::all_of(Clauses, [](OMPClause *C) {
+          return llvm::is_contained(
+              {OMPC_novariants, OMPC_nocontext, OMPC_depend},
+              C->getClauseKind());
         })) {
-      if (OMPExecutableDirective::getSingleClause<OMPNocontextClause>(
-              Clauses) &&
-          OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(
-              Clauses)) {
-        Diag(StartLoc, diag::warn_omp_dispatch_clause_novariants_nocontext);
-      }
-      annotateAStmt(getASTContext(), AStmt, this, IsClauseNoContext);
+      if (OMPExecutableDirective::getSingleClause<OMPNovariantsClause>(
+              Clauses) ||
+          OMPExecutableDirective::getSingleClause<OMPNocontextClause>(Clauses))
+        annotateAStmt(getASTContext(), AStmt, this, Clauses, StartLoc);
     }
   }
   if (Kind == OMPD_loop && BindKind == OMPC_BIND_unknown) {
diff --git a/clang/test/OpenMP/dispatch_ast_print.cpp b/clang/test/OpenMP/dispatch_ast_print.cpp
index 54ba5c19df51c7..6065f4f6e68ca9 100644
--- a/clang/test/OpenMP/dispatch_ast_print.cpp
+++ b/clang/test/OpenMP/dispatch_ast_print.cpp
@@ -4,6 +4,7 @@
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp \
 // RUN:   -fsyntax-only -verify %s
 
+// expected-no-diagnostics
 
 // RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -fopenmp \
 // RUN:   -ast-print %s | FileCheck %s --check-prefix=PRINT
diff --git a/clang/test/OpenMP/dispatch_codegen.cpp b/clang/test/OpenMP/dispatch_codegen.cpp
index c3be66c6bbc7d9..1661086d74132e 100644
--- a/clang/test/OpenMP/dispatch_codegen.cpp
+++ b/clang/test/OpenMP/dispatch_codegen.cpp
@@ -198,26 +198,24 @@ void checkNoContext_withoutVariant() {
 //
 //  #pragma omp dispatch depend(out:x)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
-// CHECK: call {{.+}}captured_stmt.9{{.+}}
 //
 //  #pragma omp dispatch depend(out:x) depend(out:y)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
-// CHECK: call {{.+}}captured_stmt.10{{.+}}
 //
 //  #pragma omp dispatch depend(out:x) novariants(cond_false)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.11{{.+}}
+// CHECK: call {{.+}}captured_stmt.9{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.12{{.+}}
+// CHECK: call {{.+}}captured_stmt.10{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 //
 //  #pragma omp dispatch depend(out:x) nocontext(cond_false)
 // CHECK: call {{.+}}kmpc_omp_taskwait_deps{{.+}}
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.13{{.+}}
+// CHECK: call {{.+}}captured_stmt.11{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.14{{.+}}
+// CHECK: call {{.+}}captured_stmt.12{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret void
 //
@@ -258,7 +256,7 @@ void checkNoContext_withoutVariant() {
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.10{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
+// CHECK: call {{.+}}foo{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.11{{.+}}
@@ -266,14 +264,6 @@ void checkNoContext_withoutVariant() {
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}__captured_stmt.12{{.+}}
-// CHECK: call {{.+}}foo{{.+}}
-// CHECK: ret void
-//
-// CHECK-LABEL: define {{.+}}__captured_stmt.13{{.+}}
-// CHECK: call {{.+}}foo_variant_dispatch{{.+}}
-// CHECK: ret void
-//
-// CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}}
 // CHECK: call {{.+}}foo_variant_allCond{{.+}}
 // CHECK: ret void
 //
@@ -288,72 +278,72 @@ void checkNoContext_withoutVariant() {
 // CHECK-LABEL: define {{.+}}without_declareVariant{{.+}}
 // CHECK-LABEL: entry:
 // CHECK: call {{.+}}bar{{.+}}
-// CHECK: call {{.+}}captured_stmt.15{{.+}}
+// CHECK: call {{.+}}captured_stmt.13{{.+}}
 // CHECK-NEXT: call {{.+}}checkNoVariants_withoutVariant{{.+}}
 // CHECK-NEXT: call {{.+}}checkNoContext_withoutVariant{{.+}}
 // CHECK-NEXT: ret{{.+}}
 //
 //  #pragma omp dispatch
-// CHECK-LABEL: define {{.+}}__captured_stmt.15{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.13{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
 //
 // CHECK-LABEL: define {{.+}}checkNoVariants_withoutVariant{{.+}}
 // CHECK-LABEL: entry:
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.16{{.+}}
+// CHECK: call {{.+}}captured_stmt.14{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.17{{.+}}
+// CHECK: call {{.+}}captured_stmt.15{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.18{{.+}}
+// CHECK: call {{.+}}captured_stmt.16{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.19{{.+}}
+// CHECK: call {{.+}}captured_stmt.17{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret{{.+}}
 //
 // CHECK-LABEL: define {{.+}}checkNoContext_withoutVariant{{.+}}
 // CHECK-LABEL: entry:
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.20{{.+}}
+// CHECK: call {{.+}}captured_stmt.18{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.21{{.+}}
+// CHECK: call {{.+}}captured_stmt.19{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK-LABEL: if.else{{.+}}
-// CHECK: call {{.+}}captured_stmt.22{{.+}}
+// CHECK: call {{.+}}captured_stmt.20{{.+}}
 // CHECK-LABEL: if.then{{.+}}
-// CHECK: call {{.+}}captured_stmt.23{{.+}}
+// CHECK: call {{.+}}captured_stmt.21{{.+}}
 // CHECK-LABEL: if.end{{.+}}
 // CHECK: ret{{.+}} 
 //
 // #pragma omp dispatch novariants(cond_true)
-// CHECK-LABEL: define {{.+}}__captured_stmt.16{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.14{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
-// CHECK-LABEL: define {{.+}}__captured_stmt.17{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.15{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
 //
 // #pragma omp dispatch novariants(cond_false)
-// CHECK-LABEL: define {{.+}}__captured_stmt.18{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.16{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
-// CHECK-LABEL: define {{.+}}__captured_stmt.19{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.17{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
 //
 // #pragma omp dispatch nocontext(cond_true)
-// CHECK-LABEL: define {{.+}}__captured_stmt.20{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.18{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
-// CHECK-LABEL: define {{.+}}__captured_stmt.21{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.19{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
 //
 // #pragma omp dispatch nocontext(cond_false)
-// CHECK-LABEL: define {{.+}}__captured_stmt.22{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.20{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
-// CHECK-LABEL: define {{.+}}__captured_stmt.23{{.+}}
+// CHECK-LABEL: define {{.+}}__captured_stmt.21{{.+}}
 // CHECK: call {{.+}}bar{{.+}}
 // CHECK: ret void
diff --git a/clang/test/OpenMP/dispatch_messages.cpp b/clang/test/OpenMP/dispatch_messages.cpp
index 41944c8516baf8..d1435b05224fe1 100644
--- a/clang/test/OpenMP/dispatch_messages.cpp
+++ b/clang/test/OpenMP/dispatch_messages.cpp
@@ -103,7 +103,7 @@ void testit_one(int dnum) {
   #pragma omp dispatch depend(in:b) depend(in:a)
   output = disp_call();
 
-  // expected-warning at +1 {{first occuring clause among 'nocontext' or 'novariants' is applied}}
+  // expected-warning at +1 {{'nocontext' clause is ignored, only 'novariants' clause is applied}}
   #pragma omp dispatch nocontext(c1) novariants(c2) depend(inout:a)
   disp_call();
 }



More information about the llvm-commits mailing list