https://github.com/zahiraam updated 
https://github.com/llvm/llvm-project/pull/192455

>From 7bed434c1a9f52203764e5e8c9166a5548e6e751 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Mon, 6 Jul 2026 13:42:58 -0700
Subject: [PATCH 1/4] Addressed review comments

---
 clang/include/clang/AST/OpenMPClause.h        |  13 ++
 clang/include/clang/AST/StmtOpenMP.h          |  68 ++++--
 clang/include/clang/AST/TextNodeDumper.h      |   1 +
 clang/include/clang/Parse/Parser.h            |  25 ++-
 clang/include/clang/Sema/SemaOpenMP.h         |  14 ++
 clang/lib/AST/StmtOpenMP.cpp                  |  58 ++++-
 clang/lib/AST/TextNodeDumper.cpp              |  11 +
 clang/lib/CodeGen/CGStmtOpenMP.cpp            |  11 +-
 clang/lib/Parse/ParseOpenMP.cpp               | 193 +++++++++++++---
 clang/lib/Sema/SemaOpenMP.cpp                 | 210 ++++++++++++++++++
 clang/lib/Serialization/ASTReaderStmt.cpp     |  21 +-
 clang/lib/Serialization/ASTWriterStmt.cpp     |  15 ++
 ...tadirective_runtime_user_condition_ast.cpp |  35 +++
 ...rective_runtime_user_condition_codegen.cpp | 140 ++++++++++++
 14 files changed, 750 insertions(+), 65 deletions(-)
 create mode 100644 
clang/test/OpenMP/metadirective_runtime_user_condition_ast.cpp
 create mode 100644 
clang/test/OpenMP/metadirective_runtime_user_condition_codegen.cpp

diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index 12959fe0c2ff0..e5791347926d8 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -9949,6 +9949,19 @@ class OMPTraitInfo {
     return false;
   }
 
+  /// Check if this trait info contains any user conditions.
+  bool hasUserCondition() const {
+    for (const OMPTraitSet &Set : Sets) {
+      if (Set.Kind != llvm::omp::TraitSet::user)
+        continue;
+      for (const OMPTraitSelector &Selector : Set.Selectors) {
+        if (Selector.Kind == llvm::omp::TraitSelector::user_condition)
+          return true;
+      }
+    }
+    return false;
+  }
+
   /// Print a human readable representation into \p OS.
   void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
 };
diff --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index dbc76e7df8ecd..c13b6527a916e 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6374,28 +6374,70 @@ class OMPMaskedDirective final : public 
OMPExecutableDirective {
 ///
 class OMPMetaDirective final : public OMPExecutableDirective {
   friend class ASTStmtReader;
+  friend class ASTStmtWriter;
   friend class OMPExecutableDirective;
-  Stmt *IfStmt;
+  unsigned NumVariants;
+  OpenMPDirectiveKind *DirectiveKinds;
+  Expr **Conditions;
+  Stmt **VariantDirectives;
 
-  OMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+  OMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc,
+                   unsigned NumVariants)
       : OMPExecutableDirective(OMPMetaDirectiveClass,
-                               llvm::omp::OMPD_metadirective, StartLoc,
-                               EndLoc) {}
-  explicit OMPMetaDirective()
+                               llvm::omp::OMPD_metadirective, StartLoc, 
EndLoc),
+        NumVariants(NumVariants), DirectiveKinds(nullptr), Conditions(nullptr),
+        VariantDirectives(nullptr) {}
+  explicit OMPMetaDirective(unsigned NumVariants)
       : OMPExecutableDirective(OMPMetaDirectiveClass,
                                llvm::omp::OMPD_metadirective, SourceLocation(),
-                               SourceLocation()) {}
+                               SourceLocation()),
+        NumVariants(NumVariants), DirectiveKinds(nullptr), Conditions(nullptr),
+        VariantDirectives(nullptr) {}
 
-  void setIfStmt(Stmt *S) { IfStmt = S; }
+  void setIfStmt(Stmt *S) { Data->getChildren()[0] = S; }
+  void setDirectiveKinds(OpenMPDirectiveKind *DK) { DirectiveKinds = DK; }
+  void setConditions(Expr **C) { Conditions = C; }
+  void setVariantDirectives(Stmt **VD) { VariantDirectives = VD; }
+  static void allocateVariantStorage(const ASTContext &C, OMPMetaDirective 
*Dir,
+                                     unsigned NumVariants);
+
+  OpenMPDirectiveKind *getDirectiveKinds() { return DirectiveKinds; }
+  Expr **getConditions() { return Conditions; }
+  Stmt **getVariantDirectives() { return VariantDirectives; }
 
 public:
-  static OMPMetaDirective *Create(const ASTContext &C, SourceLocation StartLoc,
-                                  SourceLocation EndLoc,
-                                  ArrayRef<OMPClause *> Clauses,
-                                  Stmt *AssociatedStmt, Stmt *IfStmt);
+  static OMPMetaDirective *
+  Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+         ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Stmt *IfStmt,
+         ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
+         ArrayRef<Expr *> Conditions, ArrayRef<Stmt *> VariantDirectives);
   static OMPMetaDirective *CreateEmpty(const ASTContext &C, unsigned 
NumClauses,
-                                       EmptyShell);
-  Stmt *getIfStmt() const { return IfStmt; }
+                                       unsigned NumVariants, EmptyShell);
+  Stmt *getIfStmt() const { return Data->getChildren()[0]; }
+
+  unsigned getNumVariants() const { return NumVariants; }
+
+  ArrayRef<OpenMPDirectiveKind> getDirectiveKinds() const {
+    return ArrayRef<OpenMPDirectiveKind>(DirectiveKinds, NumVariants);
+  }
+
+  ArrayRef<Expr *> getConditions() const {
+    return ArrayRef<Expr *>(Conditions, NumVariants);
+  }
+
+  ArrayRef<Stmt *> getVariantDirectives() const {
+    return ArrayRef<Stmt *>(VariantDirectives, NumVariants);
+  }
+
+  child_range children() {
+    if (!Data)
+      return child_range(child_iterator(), child_iterator());
+    return Data->getChildren();
+  }
+
+  const_child_range children() const {
+    return const_cast<OMPMetaDirective *>(this)->children();
+  }
 
   static bool classof(const Stmt *T) {
     return T->getStmtClass() == OMPMetaDirectiveClass;
diff --git a/clang/include/clang/AST/TextNodeDumper.h 
b/clang/include/clang/AST/TextNodeDumper.h
index 41ddd88a8326c..803e69f615ed2 100644
--- a/clang/include/clang/AST/TextNodeDumper.h
+++ b/clang/include/clang/AST/TextNodeDumper.h
@@ -374,6 +374,7 @@ class TextNodeDumper
   void VisitPragmaCommentDecl(const PragmaCommentDecl *D);
   void VisitPragmaDetectMismatchDecl(const PragmaDetectMismatchDecl *D);
   void VisitOMPExecutableDirective(const OMPExecutableDirective *D);
+  void VisitOMPMetaDirective(const OMPMetaDirective *D);
   void VisitOMPDeclareReductionDecl(const OMPDeclareReductionDecl *D);
   void VisitOMPRequiresDecl(const OMPRequiresDecl *D);
   void VisitOMPCapturedExprDecl(const OMPCapturedExprDecl *D);
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 163aa483a84e3..f5d4c28b0a1d6 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -6679,8 +6679,11 @@ class Parser : public CodeCompletionHandler {
   /// \param StmtCtx The context in which we're parsing the directive.
   /// \param ReadDirectiveWithinMetadirective true if directive is within a
   /// metadirective and therefore ends on the closing paren.
+  /// /// \param ConsumeDirectiveOnlyInMetadirective true if we should stop at
+  /// ')' for runtime metadirective (to parse multiple directives in sequence).
   StmtResult ParseOpenMPDeclarativeOrExecutableDirective(
-      ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective = 
false);
+      ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective = false,
+      bool ConsumeDirectiveOnlyInMetadirective = false);
 
   /// Parses executable directive.
   ///
@@ -6689,10 +6692,12 @@ class Parser : public CodeCompletionHandler {
   /// \param Loc Source location of the beginning of the directive.
   /// \param ReadDirectiveWithinMetadirective true if directive is within a
   /// metadirective and therefore ends on the closing paren.
-  StmtResult
-  ParseOpenMPExecutableDirective(ParsedStmtContext StmtCtx,
-                                 OpenMPDirectiveKind DKind, SourceLocation Loc,
-                                 bool ReadDirectiveWithinMetadirective);
+  /// /// \param ConsumeDirectiveOnlyInMetadirective true if we should stop at
+  /// ')' for runtime metadirective (to parse multiple directives in sequence).
+  StmtResult ParseOpenMPExecutableDirective(
+      ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
+      bool ReadDirectiveWithinMetadirective,
+      bool ConsumeDirectiveOnlyInMetadirective = false);
 
   /// Parses informational directive.
   ///
@@ -6701,9 +6706,17 @@ class Parser : public CodeCompletionHandler {
   /// \param Loc Source location of the beginning of the directive.
   /// \param ReadDirectiveWithinMetadirective true if directive is within a
   /// metadirective and therefore ends on the closing paren.
+  /// /// \param ConsumeDirectiveOnlyInMetadirective true if parsing only the
+  /// directive (runtime path), false if also consuming to pragma end
+  /// (compile-time).
   StmtResult ParseOpenMPInformationalDirective(
       ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
-      bool ReadDirectiveWithinMetadirective);
+      bool ReadDirectiveWithinMetadirective,
+      bool ConsumeDirectiveOnlyInMetadirective = false);
+
+  /// Skip tokens until reaching a closing ')' that matches the current nesting
+  /// level. Handles nested parentheses correctly.
+  void skipToMatchingParen();
 
   /// Parses clause of kind \a CKind for directive of a kind \a Kind.
   ///
diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index f689e227866a7..87297a7e11854 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -216,6 +216,20 @@ class SemaOpenMP : public SemaBase {
                                       Stmt *AStmt, SourceLocation StartLoc,
                                       SourceLocation EndLoc);
 
+  /// Called for metadirectives with user conditions that may require
+  /// runtime selection.
+  StmtResult ActOnOpenMPMetaDirective(
+      SourceLocation StartLoc, SourceLocation EndLoc,
+      ArrayRef<OMPTraitInfo *> TraitInfos,
+      ArrayRef<OpenMPClauseKind> ClauseKinds, ArrayRef<Expr *> Conditions,
+      ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AStmt,
+      ArrayRef<Stmt *> VariantDirectives = {});
+
+  private:
+  StmtResult createParallelDirectiveForMetadirective(Stmt *Body,
+                                                     SourceLocation StartLoc,
+                                                     SourceLocation EndLoc);
+public:
   // OpenMP directives and clauses.
   /// Called on correct id-expression from the '#pragma omp
   /// threadprivate'.
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 9d6b315effb41..1bdf50be71a7e 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -260,23 +260,61 @@ void OMPLoopDirective::setFinalsConditions(ArrayRef<Expr 
*> A) {
   llvm::copy(A, getFinalsConditions().begin());
 }
 
-OMPMetaDirective *OMPMetaDirective::Create(const ASTContext &C,
-                                           SourceLocation StartLoc,
-                                           SourceLocation EndLoc,
-                                           ArrayRef<OMPClause *> Clauses,
-                                           Stmt *AssociatedStmt, Stmt *IfStmt) 
{
-  auto *Dir = createDirective<OMPMetaDirective>(
-      C, Clauses, AssociatedStmt, /*NumChildren=*/1, StartLoc, EndLoc);
+void OMPMetaDirective::allocateVariantStorage(const ASTContext &C,
+                                              OMPMetaDirective *Dir,
+                                              unsigned NumVariants) {
+  if (NumVariants == 0)
+    return;
+
+  auto *DKs = static_cast<OpenMPDirectiveKind *>(C.Allocate(
+      NumVariants * sizeof(OpenMPDirectiveKind), 
alignof(OpenMPDirectiveKind)));
+  auto **Conds = static_cast<Expr **>(
+      C.Allocate(NumVariants * sizeof(Expr *), alignof(Expr *)));
+
+  Dir->setDirectiveKinds(DKs);
+  Dir->setConditions(Conds);
+}
+
+OMPMetaDirective *OMPMetaDirective::Create(
+    const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
+    ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Stmt *IfStmt,
+    ArrayRef<OpenMPDirectiveKind> DirectiveKinds, ArrayRef<Expr *> Conditions,
+    ArrayRef<Stmt *> VariantDirectives) {
+  assert(DirectiveKinds.size() == Conditions.size() &&
+         "DirectiveKinds and Conditions must have the same size");
+  assert((VariantDirectives.empty() ||
+          DirectiveKinds.size() == VariantDirectives.size()) &&
+         "VariantDirectives, if provided, must match DirectiveKinds size");
+  unsigned NumVariants = DirectiveKinds.size();
+  auto *Dir = createDirective<OMPMetaDirective>(C, Clauses, AssociatedStmt,
+                                                /*NumChildren=*/1, StartLoc,
+                                                EndLoc, NumVariants);
   Dir->setIfStmt(IfStmt);
+  OMPMetaDirective::allocateVariantStorage(C, Dir, NumVariants);
+  if (NumVariants > 0) {
+    std::copy(DirectiveKinds.begin(), DirectiveKinds.end(),
+              Dir->getDirectiveKinds());
+    std::copy(Conditions.begin(), Conditions.end(), Dir->getConditions());
+
+    if (!VariantDirectives.empty()) {
+      auto **VDs = static_cast<Stmt **>(
+          C.Allocate(NumVariants * sizeof(Stmt *), alignof(Stmt *)));
+      std::copy(VariantDirectives.begin(), VariantDirectives.end(), VDs);
+      Dir->setVariantDirectives(VDs);
+    }
+  }
   return Dir;
 }
 
 OMPMetaDirective *OMPMetaDirective::CreateEmpty(const ASTContext &C,
                                                 unsigned NumClauses,
+                                                unsigned NumVariants,
                                                 EmptyShell) {
-  return createEmptyDirective<OMPMetaDirective>(C, NumClauses,
-                                                /*HasAssociatedStmt=*/true,
-                                                /*NumChildren=*/1);
+  auto *Dir = createEmptyDirective<OMPMetaDirective>(
+      C, NumClauses, /*HasAssociatedStmt=*/true, /*NumChildren=*/1,
+      NumVariants);
+  OMPMetaDirective::allocateVariantStorage(C, Dir, NumVariants);
+  return Dir;
 }
 
 OMPParallelDirective *OMPParallelDirective::Create(
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 5d724e9d1d91e..b64a923722b2e 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -2657,6 +2657,17 @@ void TextNodeDumper::VisitOMPExecutableDirective(
     OS << " openmp_standalone_directive";
 }
 
+void TextNodeDumper::VisitOMPMetaDirective(const OMPMetaDirective *D) {
+  unsigned NumVariants = D->getNumVariants();
+  if (NumVariants > 0) {
+    OS << " variants=" << NumVariants;
+    ArrayRef<OpenMPDirectiveKind> DKs = D->getDirectiveKinds();
+    for (unsigned I = 0; I < NumVariants; ++I) {
+      OS << " [" << I << "]: " << getOpenMPDirectiveName(DKs[I]);
+    }
+  }
+}
+
 void TextNodeDumper::VisitOMPDeclareReductionDecl(
     const OMPDeclareReductionDecl *D) {
   dumpName(D);
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp 
b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index 18524a7c32b7a..67aee6023d1d1 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -2189,7 +2189,16 @@ void CodeGenFunction::EmitOMPParallelDirective(const 
OMPParallelDirective &S) {
 }
 
 void CodeGenFunction::EmitOMPMetaDirective(const OMPMetaDirective &S) {
-  EmitStmt(S.getIfStmt());
+  // Runtime metadirectives are transformed to if-else in Sema.
+  // For compile-time selection, just emit the associated statement (the
+  // selected variant).
+  if (Stmt *IfStmt = S.getIfStmt()) {
+    EmitStmt(IfStmt);
+    return;
+  }
+
+  // Compile-time selection: emit the selected variant's statement
+  EmitStmt(S.getAssociatedStmt());
 }
 
 namespace {
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 62715da7966d0..fa9dac1d31af9 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -325,6 +325,21 @@ 
Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) {
       getCurScope(), DRD, IsCorrect);
 }
 
+void Parser::skipToMatchingParen() {
+  int ParenDepth = 0;
+  while ((Tok.isNot(tok::r_paren) || ParenDepth != 0) &&
+         Tok.isNot(tok::annot_pragma_openmp_end) && Tok.isNot(tok::eof)) {
+    if (Tok.is(tok::l_paren))
+      ParenDepth++;
+    if (Tok.is(tok::r_paren)) {
+      if (ParenDepth == 0)
+        break;
+      ParenDepth--;
+    }
+    ConsumeAnyToken();
+  }
+}
+
 void Parser::ParseOpenMPReductionInitializerForDecl(VarDecl *OmpPrivParm) {
   // Parse declarator '=' initializer.
   // If a '==' or '+=' is found, suggest a fixit to '='.
@@ -2285,7 +2300,8 @@ Parser::DeclGroupPtrTy 
Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
 
 StmtResult Parser::ParseOpenMPExecutableDirective(
     ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
-    bool ReadDirectiveWithinMetadirective) {
+    bool ReadDirectiveWithinMetadirective,
+    bool ConsumeDirectiveOnlyInMetadirective) {
   assert(isOpenMPExecutableDirective(DKind) && "Unexpected directive 
category");
   unsigned OMPVersion = Actions.getLangOpts().OpenMP;
 
@@ -2358,9 +2374,15 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
     // If we are parsing for a directive within a metadirective, the directive
     // ends with a ')'.
     if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {
-      while (Tok.isNot(tok::annot_pragma_openmp_end))
-        ConsumeAnyToken();
-      break;
+      if (ConsumeDirectiveOnlyInMetadirective) {
+        // Runtime path: stop at ')' - let the caller handle it.
+        break;
+      } else {
+        // Compile-time path: consume everything to pragma end (old behavior).
+        while (Tok.isNot(tok::annot_pragma_openmp_end))
+          ConsumeAnyToken();
+        break;
+      }
     }
     bool HasImplicitClause = false;
     if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) {
@@ -2410,7 +2432,11 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
   // End location of the directive.
   EndLoc = Tok.getLocation();
   // Consume final annot_pragma_openmp_end.
-  ConsumeAnnotationToken();
+  // For compile-time metadirective path, we consumed up to
+  // annot_pragma_openmp_end and need to consume it. For runtime path, we
+  // stopped at ')'.
+  if (!ReadDirectiveWithinMetadirective || 
!ConsumeDirectiveOnlyInMetadirective)
+    ConsumeAnnotationToken();
 
   if (DKind == OMPD_ordered) {
     // If the depend or doacross clause is specified, the ordered construct
@@ -2479,7 +2505,8 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
 
 StmtResult Parser::ParseOpenMPInformationalDirective(
     ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
-    bool ReadDirectiveWithinMetadirective) {
+    bool ReadDirectiveWithinMetadirective,
+    bool ConsumeDirectiveOnlyInMetadirective) {
   assert(isOpenMPInformationalDirective(DKind) &&
          "Unexpected directive category");
 
@@ -2497,9 +2524,15 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
 
   while (Tok.isNot(tok::annot_pragma_openmp_end)) {
     if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {
-      while (Tok.isNot(tok::annot_pragma_openmp_end))
-        ConsumeAnyToken();
-      break;
+      if (ConsumeDirectiveOnlyInMetadirective) {
+        // Runtime path: stop at ')' - let the caller handle it.
+        break;
+      } else {
+        // Compile-time path: consume everything to pragma end.
+        while (Tok.isNot(tok::annot_pragma_openmp_end))
+          ConsumeAnyToken();
+        break;
+      }
     }
 
     OpenMPClauseKind CKind = Tok.isAnnotation()
@@ -2518,7 +2551,10 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
   }
 
   SourceLocation EndLoc = Tok.getLocation();
-  ConsumeAnnotationToken();
+  // For compile-time: consumed up to annot_pragma_openmp_end, need to consume
+  // it. For runtime: stopped at ')', don't consume anything.
+  if (!ReadDirectiveWithinMetadirective || 
!ConsumeDirectiveOnlyInMetadirective)
+    ConsumeAnnotationToken();
 
   StmtResult AssociatedStmt;
   if (HasAssociatedStatement) {
@@ -2542,7 +2578,8 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
 }
 
 StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
-    ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective) {
+    ParsedStmtContext StmtCtx, bool ReadDirectiveWithinMetadirective,
+    bool ConsumeDirectiveOnlyInMetadirective) {
   if (!ReadDirectiveWithinMetadirective)
     assert(Tok.isOneOf(tok::annot_pragma_openmp, tok::annot_attr_openmp) &&
            "Not an OpenMP directive!");
@@ -2569,7 +2606,8 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
 
   if (IsExecutable) {
     Directive = ParseOpenMPExecutableDirective(
-        StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);
+        StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective,
+        ConsumeDirectiveOnlyInMetadirective);
     assert(!Directive.isUnset() && "Executable directive remained 
unprocessed");
     return Directive;
   }
@@ -2591,6 +2629,7 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
   case OMPD_metadirective: {
     ConsumeToken();
     SmallVector<VariantMatchInfo, 4> VMIs;
+    SmallVector<OMPTraitInfo *, 4> TraitInfos;
 
     // First iteration of parsing all clauses of metadirective.
     // This iteration only parses and collects all context selector ignoring 
the
@@ -2648,19 +2687,12 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       }
 
       // Skip Directive for now. We will parse directive in the second 
iteration
-      int paren = 0;
-      while (Tok.isNot(tok::r_paren) || paren != 0) {
-        if (Tok.is(tok::l_paren))
-          paren++;
-        if (Tok.is(tok::r_paren))
-          paren--;
-        if (Tok.is(tok::annot_pragma_openmp_end)) {
-          Diag(Tok, diag::err_omp_expected_punc)
-              << getOpenMPClauseName(CKind) << 0;
-          TPA.Commit();
-          return Directive;
-        }
-        ConsumeAnyToken();
+     skipToMatchingParen();
+      if (Tok.is(tok::annot_pragma_openmp_end)) {
+        Diag(Tok, diag::err_omp_expected_punc)
+            << getOpenMPClauseName(CKind) << 0;
+        TPA.Commit();
+        return Directive;
       }
       // Parse ')'
       if (Tok.is(tok::r_paren))
@@ -2670,6 +2702,7 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       TI.getAsVariantMatchInfo(ASTContext, VMI);
 
       VMIs.push_back(VMI);
+      TraitInfos.push_back(&TI);
     }
 
     TPA.Revert();
@@ -2689,6 +2722,104 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     // A single match is returned for OpenMP 5.0
     int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
 
+    // Check if we have any user conditions that need runtime or deferred
+    // evaluation:
+    // - Value-dependent conditions (template parameters): defer until
+    // instantiation.
+    // - Non-constant conditions (runtime variables): create runtime selection.
+    bool HasNonConstantUserCondition = false;
+    for (OMPTraitInfo *TI : TraitInfos) {
+      if (TI && TI->hasUserCondition()) {
+        // Found a user condition - check if it's non-constant
+        TI->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
+          if (!IsScore && E &&
+              (E->isValueDependent() || !E->isEvaluatable(ASTContext))) {
+            HasNonConstantUserCondition = true;
+            return true;
+          }
+          return false;
+        });
+        if (HasNonConstantUserCondition)
+          break;
+      }
+    }
+
+    // If we have non-constant conditions, collect all variants and send to 
Sema
+    // Sema handles both runtime selection and re-evaluation after template
+    // instantiation.
+    if (HasNonConstantUserCondition) {
+      // Collect all variants with their conditions.
+      SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
+      SmallVector<Expr *, 4> Conditions;
+      SmallVector<OpenMPClauseKind, 4> ClauseKinds;
+      SmallVector<Stmt *, 4> VariantDirectives;
+
+      while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+        OpenMPClauseKind CKind = Tok.isAnnotation()
+                                     ? OMPC_unknown
+                                     : 
getOpenMPClauseKind(PP.getSpelling(Tok));
+        SourceLocation ClauseLoc = ConsumeToken();
+
+        // Parse '('.
+        T.consumeOpen();
+
+        Expr *Condition = nullptr;
+        if (CKind == OMPC_when) {
+          OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+          parseOMPContextSelectors(ClauseLoc, TI);
+
+          // Extract user condition if present.
+          TI.anyScoreOrCondition([&](Expr *&E, bool IsScore) {
+            if (!IsScore && E) {
+              Condition = E;
+              return true;
+            }
+            return false;
+          });
+          // Parse ':'.
+          if (Tok.is(tok::colon))
+            ConsumeAnyToken();
+        }
+
+        // Parse only the directive kind (not the full statement with body).
+        // The body will be shared across all variants and parsed after the
+        // metadirective.
+        OpenMPDirectiveKind DKind = OMPD_unknown;
+        Stmt *VariantDirective = nullptr;
+
+        if (!Tok.is(tok::r_paren)) {
+          DKind = parseOpenMPDirectiveKind(*this);
+          skipToMatchingParen();
+        }
+
+        // Parse ')'.
+        if (Tok.is(tok::r_paren))
+          T.consumeClose();
+
+        DirectiveKinds.push_back(DKind);
+        Conditions.push_back(Condition);
+        ClauseKinds.push_back(CKind);
+        VariantDirectives.push_back(VariantDirective);
+      }
+
+      SourceLocation EndLoc = Tok.getLocation();
+      ConsumeAnnotationToken();
+
+      StmtResult AssocStmt = ParseStatement();
+      if (AssocStmt.isInvalid())
+        return StmtError();
+
+      // For runtime metadirectives, pass empty VariantDirectives.
+      // The transformation to if-else happens in Sema.
+      SmallVector<Stmt *, 4> EmptyVariantDirectives(DirectiveKinds.size(),
+                                                    nullptr);
+
+      // Pass to Sema to build the runtime metadirective.
+      return Actions.OpenMP().ActOnOpenMPMetaDirective(
+          Loc, EndLoc, TraitInfos, ClauseKinds, Conditions, DirectiveKinds,
+          AssocStmt.get(), EmptyVariantDirectives);
+    }
+
     int Idx = 0;
     // In OpenMP 5.0 metadirective is either replaced by another directive or
     // ignored.
@@ -2699,15 +2830,8 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
       if (Idx++ != BestIdx) {
         ConsumeToken();  // Consume clause name
         T.consumeOpen(); // Consume '('
-        int paren = 0;
         // Skip everything inside the clause
-        while (Tok.isNot(tok::r_paren) || paren != 0) {
-          if (Tok.is(tok::l_paren))
-            paren++;
-          if (Tok.is(tok::r_paren))
-            paren--;
-          ConsumeAnyToken();
-        }
+        skipToMatchingParen();
         // Parse ')'
         if (Tok.is(tok::r_paren))
           T.consumeClose();
@@ -2912,7 +3036,8 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
   case OMPD_assume: {
     ConsumeToken();
     Directive = ParseOpenMPInformationalDirective(
-        StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);
+        StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective,
+        ConsumeDirectiveOnlyInMetadirective);
     assert(!Directive.isUnset() &&
            "Informational directive remains unprocessed");
     return Directive;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0f45a21c5e461..7223c3d2904c0 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3764,6 +3764,216 @@ StmtResult 
SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
                                     AStmt);
 }
 
+StmtResult SemaOpenMP::createParallelDirectiveForMetadirective(
+    Stmt *Body, SourceLocation StartLoc, SourceLocation EndLoc) {
+  DeclarationNameInfo DirName;
+  DSAStack->push(llvm::omp::OMPD_parallel, DirName, SemaRef.getCurScope(),
+                 StartLoc);
+
+  ActOnOpenMPRegionStart(llvm::omp::OMPD_parallel, SemaRef.getCurScope());
+
+  StmtResult CapturedBody = ActOnOpenMPRegionEnd(Body, /*Clauses=*/{});
+
+  if (!CapturedBody.isUsable()) {
+    DSAStack->pop();
+    return StmtError();
+  }
+
+  StmtResult ParallelStmt = ActOnOpenMPParallelDirective(
+      /*Clauses=*/{}, CapturedBody.get(), StartLoc, EndLoc);
+
+  DSAStack->pop();
+
+  if (!ParallelStmt.isUsable())
+    return StmtError();
+
+  return ParallelStmt;
+}
+
+StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
+    SourceLocation StartLoc, SourceLocation EndLoc,
+    ArrayRef<OMPTraitInfo *> TraitInfos, ArrayRef<OpenMPClauseKind> 
ClauseKinds,
+    ArrayRef<Expr *> Conditions, ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
+    Stmt *AStmt, ArrayRef<Stmt *> VariantDirectives) {
+
+  assert(TraitInfos.size() == ClauseKinds.size() &&
+         ClauseKinds.size() == Conditions.size() &&
+         Conditions.size() == DirectiveKinds.size() &&
+         "Mismatched array sizes for metadirective variants");
+  assert((VariantDirectives.empty() ||
+          VariantDirectives.size() == DirectiveKinds.size()) &&
+         "VariantDirectives, if provided, must match DirectiveKinds size");
+
+  if (TraitInfos.empty())
+    return StmtError();
+
+  ASTContext &Context = getASTContext();
+
+  // Check if all user conditions are constant.
+  bool AllConstant = true;
+  for (Expr *Condition : Conditions) {
+    if (Condition && !Condition->isEvaluatable(Context)) {
+      AllConstant = false;
+      break;
+    }
+  }
+
+  if (AllConstant) {
+    // All conditions are compile-time constant - evaluate and select.
+    for (unsigned I = 0; I < Conditions.size(); ++I) {
+      bool ShouldSelect = false;
+
+      if (ClauseKinds[I] == OMPC_when) {
+        // Evaluate the user condition.
+        if (Conditions[I]) {
+          Expr::EvalResult Result;
+          if (Conditions[I]->EvaluateAsInt(Result, Context)) {
+            ShouldSelect = Result.Val.getInt().getBoolValue();
+          }
+        }
+      } else if (ClauseKinds[I] == OMPC_otherwise ||
+                 ClauseKinds[I] == OMPC_default) {
+        // otherwise/default always matches.
+        ShouldSelect = true;
+      }
+      if (ShouldSelect) {
+        OpenMPDirectiveKind SelectedKind = DirectiveKinds[I];
+
+        // If it's "nothing" or unknown, just return the statement.
+        if (SelectedKind == OMPD_unknown || SelectedKind == OMPD_nothing)
+          return AStmt;
+
+        // Create the selected directive.
+        if (SelectedKind == OMPD_parallel) {
+          DeclarationNameInfo DirName;
+          DSAStack->push(OMPD_parallel, DirName, SemaRef.getCurScope(),
+                         StartLoc);
+          StmtResult ParallelStmt =
+              createParallelDirectiveForMetadirective(AStmt, StartLoc, EndLoc);
+          DSAStack->pop();
+
+          if (ParallelStmt.isUsable())
+            return ParallelStmt;
+          return StmtError();
+        } else {
+          // TODO: Handle other directive kinds
+          // For now, just return the statement
+          return AStmt;
+        }
+      }
+    }
+    return AStmt;
+  }
+
+  // At least one condition is runtime - transform to if-else AST.
+  // This allows normal OpenMP infrastructure to create CapturedStmts.
+
+  // Push a dummy entry onto DSA stack so that ActOnOpenMPRegionStart has
+  // context. We use the metadirective itself as the dummy entry.
+  DeclarationNameInfo DirName;
+  DSAStack->push(OMPD_unknown, DirName, SemaRef.getCurScope(), StartLoc);
+
+  // For now, handle simple case: 2 variants (when + otherwise).
+  if (DirectiveKinds.size() == 2 && Conditions[0] && !Conditions[1]) {
+
+    // Build: if (condition) { #pragma omp directive1 { body } } else { body }.
+    Expr *IfCondition = Conditions[0];
+    OpenMPDirectiveKind ThenDK = DirectiveKinds[0];
+    OpenMPDirectiveKind ElseDK = DirectiveKinds[1];
+
+    // Check if both branches would execute the body identically (both are
+    // nothing/unknown).
+    // In this case, don't create an if-else - just execute the body once.
+    bool ThenIsNothing = (ThenDK == OMPD_unknown || ThenDK == OMPD_nothing);
+    bool ElseIsNothing = (ElseDK == OMPD_unknown || ElseDK == OMPD_nothing);
+    if (ThenIsNothing && ElseIsNothing) {
+      // Both branches would execute the same body - no need for if-else.
+      DSAStack->pop();
+      return AStmt;
+    }
+    SmallVector<Stmt *, 2> CreatedVariantDirectives;
+    // Create the then-branch directive.
+    Stmt *ThenStmt = nullptr;
+    Stmt *ThenDirective = nullptr;
+    if (ThenDK == OMPD_parallel) {
+      StmtResult ParallelStmt =
+          createParallelDirectiveForMetadirective(AStmt, StartLoc, EndLoc);
+      if (!ParallelStmt.isUsable())
+        return StmtError();
+      ThenDirective = ParallelStmt.get();
+      ThenStmt = ThenDirective;
+    } else if (ThenDK == OMPD_unknown || ThenDK == OMPD_nothing) {
+      ThenStmt = AStmt;
+      ThenDirective = nullptr;
+    } else {
+      // TODO: Handle other directive kinds.
+      ThenStmt = AStmt;
+      ThenDirective = nullptr;
+    }
+    CreatedVariantDirectives.push_back(ThenDirective);
+
+    // Create the else-branch directive.
+    Stmt *ElseStmt = nullptr;
+    Stmt *ElseDirective = nullptr;
+    if (ElseDK == OMPD_unknown || ElseDK == OMPD_nothing) {
+      ElseStmt = AStmt;
+      ElseDirective = nullptr;
+    } else if (ElseDK == OMPD_parallel) {
+      StmtResult ParallelStmt =
+          createParallelDirectiveForMetadirective(AStmt, StartLoc, EndLoc);
+      if (!ParallelStmt.isUsable())
+        return StmtError();
+      ElseDirective = ParallelStmt.get();
+      ElseStmt = ElseDirective;
+    } else {
+      // TODO: Handle other directive kinds.
+      ElseStmt = AStmt;
+      ElseDirective = nullptr;
+    }
+    CreatedVariantDirectives.push_back(ElseDirective);
+    // Build the IfStmt.
+    IfStmt *RuntimeIfStmt =
+        IfStmt::Create(Context, StartLoc, IfStatementKind::Ordinary,
+                       /*Init=*/nullptr, /*Var=*/nullptr, IfCondition, 
StartLoc,
+                       StartLoc, ThenStmt, StartLoc, ElseStmt);
+
+    // Pop the dummy DSA stack entry.
+    DSAStack->pop();
+    return OMPMetaDirective::Create(Context, StartLoc, EndLoc, /*Clauses=*/{},
+                                    AStmt, RuntimeIfStmt, DirectiveKinds,
+                                    Conditions, CreatedVariantDirectives);
+  }
+
+  // Pop the dummy DSA stack entry if we didn't handle the 2-variant case.
+  DSAStack->pop();
+  // Fallback: At least one condition is runtime - create directive nodes if we
+  // have CapturedStmts.
+  SmallVector<Stmt *, 4> CreatedVariantDirectives;
+  for (unsigned I = 0; I < DirectiveKinds.size(); ++I) {
+    OpenMPDirectiveKind DK = DirectiveKinds[I];
+
+    if (DK == OMPD_unknown || DK == OMPD_nothing) {
+      // For nothing/unknown, no directive node needed.
+      CreatedVariantDirectives.push_back(nullptr);
+    } else if (I < VariantDirectives.size() && VariantDirectives[I]) {
+      // We have a CapturedStmt from the parser - create the directive.
+      Stmt *CapturedStmt = VariantDirectives[I];
+      StmtResult DirectiveStmt = ActOnOpenMPExecutableDirective(
+          DK, /*DirName=*/{}, /*CancelRegion=*/OMPD_unknown,
+          /*Clauses=*/{}, CapturedStmt, StartLoc, EndLoc);
+
+      CreatedVariantDirectives.push_back(
+          DirectiveStmt.isUsable() ? DirectiveStmt.get() : nullptr);
+    } else {
+      // No CapturedStmt provided - codegen will handle it
+      CreatedVariantDirectives.push_back(nullptr);
+    }
+  }
+  return OMPMetaDirective::Create(Context, StartLoc, EndLoc, /*Clauses=*/{},
+                                  AStmt, /*IfStmt=*/nullptr, DirectiveKinds,
+                                  Conditions, CreatedVariantDirectives);
+}
+
 OMPRequiresDecl *
 SemaOpenMP::CheckOMPRequiresDecl(SourceLocation Loc,
                                  ArrayRef<OMPClause *> ClauseList) {
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 87cec16a76323..59b08013e946e 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2518,7 +2518,25 @@ void 
ASTStmtReader::VisitOMPMetaDirective(OMPMetaDirective *D) {
   VisitStmt(D);
   // The NumClauses field was read in ReadStmtFromStream.
   Record.skipInts(1);
+  unsigned NumVariants = Record.readInt();
   VisitOMPExecutableDirective(D);
+
+  // Read directive kinds and conditions.
+  SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
+  for (unsigned I = 0; I < NumVariants; ++I)
+    DirectiveKinds.push_back(
+        static_cast<OpenMPDirectiveKind>(Record.readInt()));
+  std::copy(DirectiveKinds.begin(), DirectiveKinds.end(),
+            D->getDirectiveKinds());
+
+  for (unsigned I = 0; I < NumVariants; ++I)
+    D->getConditions()[I] = Record.readSubExpr();
+
+  // Read variant directives if present.
+  if (D->getVariantDirectives()) {
+    for (unsigned I = 0; I < NumVariants; ++I)
+      D->getVariantDirectives()[I] = Record.readSubStmt();
+  }
 }
 
 void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
@@ -3692,7 +3710,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
 
     case STMT_OMP_META_DIRECTIVE:
       S = OMPMetaDirective::CreateEmpty(
-          Context, Record[ASTStmtReader::NumStmtFields], Empty);
+          Context, Record[ASTStmtReader::NumStmtFields],
+          Record[ASTStmtReader::NumStmtFields + 1], Empty);
       break;
 
     case STMT_OMP_PARALLEL_DIRECTIVE:
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index 70477f4cf4001..b9be4bafe7770 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2531,7 +2531,22 @@ void 
ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
 void ASTStmtWriter::VisitOMPMetaDirective(OMPMetaDirective *D) {
   VisitStmt(D);
   Record.push_back(D->getNumClauses());
+  Record.push_back(D->getNumVariants());
   VisitOMPExecutableDirective(D);
+  // Write directive kinds and conditions.
+   const OMPMetaDirective *ConstD = D;
+  for (auto DK : ConstD->getDirectiveKinds())
+    Record.push_back(static_cast<unsigned>(DK));
+
+  for (auto *E : ConstD->getConditions())
+    Record.AddStmt(E);
+
+  // Write variant directives if present.
+  ArrayRef<Stmt *> Variants = ConstD->getVariantDirectives();
+  if (!Variants.empty()) {
+    for (auto *S : Variants)
+      Record.AddStmt(S);
+  }
   Code = serialization::STMT_OMP_META_DIRECTIVE;
 }
 
diff --git a/clang/test/OpenMP/metadirective_runtime_user_condition_ast.cpp 
b/clang/test/OpenMP/metadirective_runtime_user_condition_ast.cpp
new file mode 100644
index 0000000000000..51b8ca5be1cce
--- /dev/null
+++ b/clang/test/OpenMP/metadirective_runtime_user_condition_ast.cpp
@@ -0,0 +1,35 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=52 -std=c++11 \
+// RUN: -ast-dump %s | FileCheck %s
+
+// expected-no-diagnostics 
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_runtime_condition
+// CHECK: OMPMetaDirective {{.*}} variants=2
+// CHECK-NEXT: IfStmt {{.*}} has_else
+// CHECK-NEXT: DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'flag' 'int'
+// CHECK-NEXT: OMPParallelDirective
+// CHECK-NEXT: CapturedStmt
+// CHECK-NEXT: CapturedDecl
+// CHECK-NEXT: CompoundStmt
+// CHECK-NEXT: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} x 'int'
+// CHECK: CompoundStmt
+// CHECK-NEXT: DeclStmt
+void test_runtime_condition(int flag) {
+  #pragma omp metadirective when(user={condition(flag)}: parallel) otherwise()
+  {
+    int x = 0;
+  }
+}
+
+// CHECK-LABEL: FunctionDecl {{.*}} test_both_nothing
+// CHECK-NOT: IfStmt
+// CHECK: CompoundStmt
+// CHECK: DeclStmt
+// CHECK-NEXT: VarDecl {{.*}} x 'int'
+void test_both_nothing(int flag) {
+#pragma omp metadirective when(user={condition(flag)}: nothing) otherwise()
+  {
+    int x = 0;
+  }
+}
diff --git a/clang/test/OpenMP/metadirective_runtime_user_condition_codegen.cpp 
b/clang/test/OpenMP/metadirective_runtime_user_condition_codegen.cpp
new file mode 100644
index 0000000000000..c95702b435538
--- /dev/null
+++ b/clang/test/OpenMP/metadirective_runtime_user_condition_codegen.cpp
@@ -0,0 +1,140 @@
+// RUN: %clang_cc1 -verify -fopenmp -fopenmp-version=52 -std=c++11 \
+// RUN: -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+
+// expected-no-diagnostics
+
+// Test runtime selection with non-constant user condition
+// Runtime metadirectives are transformed to if-else in Sema
+
+void test_runtime_condition(int flag) {
+// CHECK-LABEL: define {{.*}} void @_Z22test_runtime_conditioni(i32 noundef 
%flag)
+// CHECK: %flag.addr = alloca i32, align 4
+// CHECK: %x = alloca i32, align 4
+// CHECK: store i32 %flag, ptr %flag.addr, align 4
+// CHECK: [[LOAD:%.*]] = load i32, ptr %flag.addr, align 4
+// CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[LOAD]], 0
+// CHECK: br i1 [[TOBOOL]], label %if.then, label %if.else
+// CHECK: if.then:
+// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @{{[0-9]+}}, 
i32 0, ptr @_Z22test_runtime_conditioni.omp_outlined)
+// CHECK: br label %if.end
+// CHECK: if.else:
+// CHECK: store i32 0, ptr %x, align 4
+// CHECK: br label %if.end
+// CHECK: if.end:
+// CHECK: ret void
+  #pragma omp metadirective when(user={condition(flag)}: parallel) otherwise()
+  {
+    int x = 0;
+  }
+}
+// CHECK: define internal void @_Z22test_runtime_conditioni.omp_outlined(ptr 
{{.*}}, ptr {{.*}})
+
+void test_runtime_condition_two_variants(int flag) {
+// CHECK-LABEL: define {{.*}} void 
@_Z35test_runtime_condition_two_variantsi(i32 noundef %flag)
+// CHECK: %flag.addr = alloca i32, align 4
+// CHECK: %i = alloca i32, align 4
+// CHECK: store i32 %flag, ptr %flag.addr, align 4
+// CHECK: [[LOAD:%.*]] = load i32, ptr %flag.addr, align 4
+// CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[LOAD]], 0
+// CHECK: br i1 [[TOBOOL]], label %if.then, label %if.else
+// CHECK: if.then:
+// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @{{[0-9]+}}, 
i32 0, ptr @_Z35test_runtime_condition_two_variantsi.omp_outlined)
+// CHECK: br label %if.end
+// CHECK: if.else:
+// CHECK: store i32 0, ptr %i, align 4
+// CHECK: br label %for.cond
+// CHECK: for.cond:
+// CHECK: [[LOAD_I:%.*]] = load i32, ptr %i, align 4
+// CHECK: [[CMP:%.*]] = icmp slt i32 [[LOAD_I]], 10
+// CHECK: br i1 [[CMP]], label %for.body, label %for.end
+// CHECK: for.body:
+// CHECK: br label %for.inc
+// CHECK: for.inc:
+// CHECK: [[LOAD_I2:%.*]] = load i32, ptr %i, align 4
+// CHECK: [[INC:%.*]] = add nsw i32 [[LOAD_I2]], 1
+// CHECK: store i32 [[INC]], ptr %i, align 4
+// CHECK: br label %for.cond
+// CHECK: for.end:
+// CHECK: br label %if.end
+// CHECK: if.end:
+// CHECK: ret void
+  #pragma omp metadirective when(user={condition(flag)}: parallel) 
otherwise(parallel for)
+  for (int i = 0; i < 10; i++)
+    ;
+}
+// CHECK: define internal void 
@_Z35test_runtime_condition_two_variantsi.omp_outlined(ptr {{.*}}, ptr {{.*}})
+
+// Test with clauses on the parallel directive
+void test_runtime_with_clauses(int flag, int n) {
+// CHECK-LABEL: define {{.*}}void @_Z25test_runtime_with_clausesii(i32 noundef 
%flag, i32 noundef %n)
+// CHECK: %flag.addr = alloca i32, align 4
+// CHECK: %n.addr = alloca i32, align 4
+// CHECK: store i32 %flag, ptr %flag.addr, align 4
+// CHECK: store i32 %n, ptr %n.addr, align 4
+// CHECK: [[LOAD:%.*]] = load i32, ptr %flag.addr, align 4
+// CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[LOAD]], 0
+// CHECK: br i1 [[TOBOOL]], label %if.then, label %if.else
+// CHECK: if.then:
+// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call
+// CHECK: br label %if.end
+// CHECK: if.else:
+// CHECK: br label %if.end
+// CHECK: if.end:
+// CHECK: ret void
+#pragma omp metadirective when(user={condition(flag)}: parallel 
num_threads(n)) otherwise()
+  {
+    int x = 0;
+  }
+}
+// CHECK: define internal void 
@_Z25test_runtime_with_clausesii.omp_outlined(ptr {{.*}}, ptr {{.*}})
+
+  void test_runtime_multiple_stmts(int flag) {
+// CHECK-LABEL: define {{.*}}void @_Z27test_runtime_multiple_stmtsi(i32 
noundef %flag)
+// CHECK: [[LOAD:%.*]] = load i32, ptr %flag.addr, align 4
+// CHECK: [[TOBOOL:%.*]] = icmp ne i32 [[LOAD]], 0
+// CHECK: br i1 [[TOBOOL]], label %if.then, label %if.else
+// CHECK: if.then:
+// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call
+// CHECK: br label %if.end
+// CHECK: if.else:
+// CHECK: store i32 1, ptr %x
+// CHECK: store i32 2, ptr %y
+// CHECK: store i32 3, ptr %z
+// CHECK: br label %if.end
+// CHECK: if.end:
+// CHECK: ret void
+  #pragma omp metadirective when(user={condition(flag)}: parallel) otherwise()
+  {
+    int x = 1;
+    int y = 2;
+    int z = 3;
+  }
+}
+// CHECK:define internal void 
@_Z27test_runtime_multiple_stmtsi.omp_outlined(ptr {{.*}}, ptr {{.*}})
+
+// Test that compile-time constant condition still works (no if-else generated)
+void test_compile_time_constant(void) {
+// CHECK-LABEL: define {{.*}}void @_Z26test_compile_time_constantv()
+// CHECK-NOT: br i1
+// CHECK: call void (ptr, i32, ptr, ...) @__kmpc_fork_call
+// CHECK: ret void
+  #pragma omp metadirective when(user={condition(1)}: parallel) otherwise()
+  {
+    int x = 0;
+  }
+}
+// CHECK: define internal void 
@_Z26test_compile_time_constantv.omp_outlined(ptr {{.*}}, ptr {{.*}})
+
+// Test when both branches are "nothing" - no if-else is generated
+void test_runtime_otherwise(int flag) {
+// CHECK-LABEL: define {{.*}} @_Z22test_runtime_otherwisei
+// CHECK: %flag.addr = alloca i32
+// CHECK: %x = alloca i32
+// CHECK: store i32 %flag, ptr %flag.addr
+// CHECK: store i32 0, ptr %x
+// CHECK: ret void
+  #pragma omp metadirective when(user={condition(flag)}: nothing) otherwise()
+  {
+    int x = 0;
+  }
+}

>From baed54545dac94c0091128d607c9fe9113c11531 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Wed, 15 Jul 2026 08:34:52 -0700
Subject: [PATCH 2/4] Addressed issues raised in previous comments

---
 clang/include/clang/AST/OpenMPClause.h    |  1 +
 clang/include/clang/AST/StmtOpenMP.h      | 87 ++++++++++++++++++-----
 clang/include/clang/Sema/SemaOpenMP.h     |  3 +-
 clang/lib/AST/StmtOpenMP.cpp              | 65 ++++++++++-------
 clang/lib/Parse/ParseOpenMP.cpp           | 77 +++++++++++++++-----
 clang/lib/Sema/SemaOpenMP.cpp             | 29 ++++----
 clang/lib/Serialization/ASTReaderStmt.cpp |  6 +-
 clang/lib/Serialization/ASTWriterStmt.cpp |  2 +-
 8 files changed, 187 insertions(+), 83 deletions(-)

diff --git a/clang/include/clang/AST/OpenMPClause.h 
b/clang/include/clang/AST/OpenMPClause.h
index e5791347926d8..b5486d24f0d9d 100644
--- a/clang/include/clang/AST/OpenMPClause.h
+++ b/clang/include/clang/AST/OpenMPClause.h
@@ -9995,6 +9995,7 @@ class OMPChildren final
   friend TrailingObjects;
   friend class OMPClauseReader;
   friend class OMPExecutableDirective;
+  friend class OMPMetaDirective;
   template <typename T> friend class OMPDeclarativeDirective;
 
   /// Numbers of clauses.
diff --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index c13b6527a916e..5e9c6dacc31cd 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6377,33 +6377,81 @@ class OMPMetaDirective final : public 
OMPExecutableDirective {
   friend class ASTStmtWriter;
   friend class OMPExecutableDirective;
   unsigned NumVariants;
-  OpenMPDirectiveKind *DirectiveKinds;
-  Expr **Conditions;
-  Stmt **VariantDirectives;
 
   OMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc,
                    unsigned NumVariants)
       : OMPExecutableDirective(OMPMetaDirectiveClass,
                                llvm::omp::OMPD_metadirective, StartLoc, 
EndLoc),
-        NumVariants(NumVariants), DirectiveKinds(nullptr), Conditions(nullptr),
-        VariantDirectives(nullptr) {}
+        NumVariants(NumVariants) {}
   explicit OMPMetaDirective(unsigned NumVariants)
       : OMPExecutableDirective(OMPMetaDirectiveClass,
                                llvm::omp::OMPD_metadirective, SourceLocation(),
                                SourceLocation()),
-        NumVariants(NumVariants), DirectiveKinds(nullptr), Conditions(nullptr),
-        VariantDirectives(nullptr) {}
+        NumVariants(NumVariants) {}
 
   void setIfStmt(Stmt *S) { Data->getChildren()[0] = S; }
-  void setDirectiveKinds(OpenMPDirectiveKind *DK) { DirectiveKinds = DK; }
-  void setConditions(Expr **C) { Conditions = C; }
-  void setVariantDirectives(Stmt **VD) { VariantDirectives = VD; }
-  static void allocateVariantStorage(const ASTContext &C, OMPMetaDirective 
*Dir,
-                                     unsigned NumVariants);
 
-  OpenMPDirectiveKind *getDirectiveKinds() { return DirectiveKinds; }
-  Expr **getConditions() { return Conditions; }
-  Stmt **getVariantDirectives() { return VariantDirectives; }
+  // Helper to calculate the aligned offset to Conditions array.
+  size_t offsetToConditions() const {
+    return llvm::alignTo(NumVariants * sizeof(OpenMPDirectiveKind),
+                         alignof(Expr *));
+  }
+
+  // Helper to calculate total size needed for trailing arrays.
+  static size_t sizeOfTrailingArrays(unsigned NumVariants) {
+    size_t DirectiveKindsSize = NumVariants * sizeof(OpenMPDirectiveKind);
+    size_t ConditionsSize = NumVariants * sizeof(Expr *);
+    size_t VariantDirectivesSize = NumVariants * sizeof(Stmt *);
+    return llvm::alignTo(DirectiveKindsSize, alignof(Expr *)) + ConditionsSize 
+
+           VariantDirectivesSize;
+  }
+
+  // Helper to allocate memory for OMPMetaDirective with trailing arrays and
+  // OMPChildren. Returns a pair of (main memory, children memory).
+  static std::pair<void *, void *> allocateMemory(const ASTContext &C,
+                                                  unsigned NumVariants,
+                                                  unsigned NumClauses,
+                                                  unsigned NumChildren);
+
+  // Helper to get the trailing storage for arrays.
+  // Layout:
+  // 
[OMPMetaDirective][DirectiveKinds...][padding][Conditions...][VariantDirectives...]
+  // Each array is properly aligned for its element type.
+  OpenMPDirectiveKind *getTrailingDirectiveKinds() {
+    return reinterpret_cast<OpenMPDirectiveKind *>(this + 1);
+  }
+
+  const OpenMPDirectiveKind *getTrailingDirectiveKinds() const {
+    return reinterpret_cast<const OpenMPDirectiveKind *>(this + 1);
+  }
+
+  Expr **getTrailingConditions() {
+    return reinterpret_cast<Expr **>(
+        reinterpret_cast<char *>(getTrailingDirectiveKinds()) +
+        offsetToConditions());
+  }
+
+  const Expr *const *getTrailingConditions() const {
+    return reinterpret_cast<const Expr *const *>(
+        reinterpret_cast<const char *>(getTrailingDirectiveKinds()) +
+        offsetToConditions());
+  }
+
+  Stmt **getTrailingVariantDirectives() {
+    return reinterpret_cast<Stmt **>(getTrailingConditions() + NumVariants);
+  }
+
+  const Stmt *const *getTrailingVariantDirectives() const {
+    return reinterpret_cast<const Stmt *const *>(getTrailingConditions() +
+                                                 NumVariants);
+  }
+
+  OpenMPDirectiveKind *getDirectiveKinds() {
+    return getTrailingDirectiveKinds();
+  }
+  Expr **getConditions() { return getTrailingConditions(); }
+
+  Stmt **getVariantDirectives() { return getTrailingVariantDirectives(); }
 
 public:
   static OMPMetaDirective *
@@ -6418,15 +6466,18 @@ class OMPMetaDirective final : public 
OMPExecutableDirective {
   unsigned getNumVariants() const { return NumVariants; }
 
   ArrayRef<OpenMPDirectiveKind> getDirectiveKinds() const {
-    return ArrayRef<OpenMPDirectiveKind>(DirectiveKinds, NumVariants);
+    return ArrayRef<OpenMPDirectiveKind>(getTrailingDirectiveKinds(),
+                                         NumVariants);
   }
 
   ArrayRef<Expr *> getConditions() const {
-    return ArrayRef<Expr *>(Conditions, NumVariants);
+    return ArrayRef<Expr *>(const_cast<Expr **>(getTrailingConditions()),
+                            NumVariants);
   }
 
   ArrayRef<Stmt *> getVariantDirectives() const {
-    return ArrayRef<Stmt *>(VariantDirectives, NumVariants);
+    return ArrayRef<Stmt *>(const_cast<Stmt 
**>(getTrailingVariantDirectives()),
+                            NumVariants);
   }
 
   child_range children() {
diff --git a/clang/include/clang/Sema/SemaOpenMP.h 
b/clang/include/clang/Sema/SemaOpenMP.h
index 87297a7e11854..2dabdfd8857ad 100644
--- a/clang/include/clang/Sema/SemaOpenMP.h
+++ b/clang/include/clang/Sema/SemaOpenMP.h
@@ -225,10 +225,11 @@ class SemaOpenMP : public SemaBase {
       ArrayRef<OpenMPDirectiveKind> DirectiveKinds, Stmt *AStmt,
       ArrayRef<Stmt *> VariantDirectives = {});
 
-  private:
+private:
   StmtResult createParallelDirectiveForMetadirective(Stmt *Body,
                                                      SourceLocation StartLoc,
                                                      SourceLocation EndLoc);
+
 public:
   // OpenMP directives and clauses.
   /// Called on correct id-expression from the '#pragma omp
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 1bdf50be71a7e..f055b9935e37e 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -260,19 +260,19 @@ void OMPLoopDirective::setFinalsConditions(ArrayRef<Expr 
*> A) {
   llvm::copy(A, getFinalsConditions().begin());
 }
 
-void OMPMetaDirective::allocateVariantStorage(const ASTContext &C,
-                                              OMPMetaDirective *Dir,
-                                              unsigned NumVariants) {
-  if (NumVariants == 0)
-    return;
-
-  auto *DKs = static_cast<OpenMPDirectiveKind *>(C.Allocate(
-      NumVariants * sizeof(OpenMPDirectiveKind), 
alignof(OpenMPDirectiveKind)));
-  auto **Conds = static_cast<Expr **>(
-      C.Allocate(NumVariants * sizeof(Expr *), alignof(Expr *)));
-
-  Dir->setDirectiveKinds(DKs);
-  Dir->setConditions(Conds);
+std::pair<void *, void *>
+OMPMetaDirective::allocateMemory(const ASTContext &C, unsigned NumVariants,
+                                 unsigned NumClauses, unsigned NumChildren) {
+  size_t ArraysSize = OMPMetaDirective::sizeOfTrailingArrays(NumVariants);
+  void *Mem = C.Allocate(
+      sizeof(OMPMetaDirective) + ArraysSize +
+          llvm::alignTo(OMPChildren::totalSizeToAlloc<OMPClause *, Stmt *>(
+                            NumClauses, NumChildren),
+                        alignof(OMPChildren)),
+      alignof(OMPMetaDirective));
+  void *ChildrenMem =
+      reinterpret_cast<char *>(Mem) + sizeof(OMPMetaDirective) + ArraysSize;
+  return {Mem, ChildrenMem};
 }
 
 OMPMetaDirective *OMPMetaDirective::Create(
@@ -286,22 +286,29 @@ OMPMetaDirective *OMPMetaDirective::Create(
           DirectiveKinds.size() == VariantDirectives.size()) &&
          "VariantDirectives, if provided, must match DirectiveKinds size");
   unsigned NumVariants = DirectiveKinds.size();
-  auto *Dir = createDirective<OMPMetaDirective>(C, Clauses, AssociatedStmt,
-                                                /*NumChildren=*/1, StartLoc,
-                                                EndLoc, NumVariants);
+
+  // Allocate memory for OMPMetaDirective with trailing arrays and OMPChildren.
+  // Layout:
+  // 
[OMPMetaDirective][DirectiveKinds...][padding][Conditions...][VariantDirectives...][OMPChildren]
+  auto [Mem, ChildrenMem] =
+      allocateMemory(C, NumVariants, Clauses.size(),
+                     /*NumChildren=*/1 + (AssociatedStmt ? 1 : 0));
+  auto *Data = OMPChildren::Create(ChildrenMem, Clauses, AssociatedStmt,
+                                   /*NumChildren=*/1);
+  auto *Dir = new (Mem) OMPMetaDirective(StartLoc, EndLoc, NumVariants);
+  Dir->Data = Data;
   Dir->setIfStmt(IfStmt);
-  OMPMetaDirective::allocateVariantStorage(C, Dir, NumVariants);
   if (NumVariants > 0) {
     std::copy(DirectiveKinds.begin(), DirectiveKinds.end(),
               Dir->getDirectiveKinds());
     std::copy(Conditions.begin(), Conditions.end(), Dir->getConditions());
 
-    if (!VariantDirectives.empty()) {
-      auto **VDs = static_cast<Stmt **>(
-          C.Allocate(NumVariants * sizeof(Stmt *), alignof(Stmt *)));
-      std::copy(VariantDirectives.begin(), VariantDirectives.end(), VDs);
-      Dir->setVariantDirectives(VDs);
-    }
+    if (!VariantDirectives.empty())
+      std::copy(VariantDirectives.begin(), VariantDirectives.end(),
+                Dir->getVariantDirectives());
+    else
+      // Initialize VariantDirectives to nullptr.
+      std::fill_n(Dir->getVariantDirectives(), NumVariants, nullptr);
   }
   return Dir;
 }
@@ -310,10 +317,14 @@ OMPMetaDirective *OMPMetaDirective::CreateEmpty(const 
ASTContext &C,
                                                 unsigned NumClauses,
                                                 unsigned NumVariants,
                                                 EmptyShell) {
-  auto *Dir = createEmptyDirective<OMPMetaDirective>(
-      C, NumClauses, /*HasAssociatedStmt=*/true, /*NumChildren=*/1,
-      NumVariants);
-  OMPMetaDirective::allocateVariantStorage(C, Dir, NumVariants);
+  // Allocate memory for empty OMPMetaDirective.
+  auto [Mem, ChildrenMem] =
+      allocateMemory(C, NumVariants, NumClauses, /*NumChildren=*/1 + 1);
+  auto *Data =
+      OMPChildren::CreateEmpty(ChildrenMem, NumClauses,
+                               /*HasAssociatedStmt=*/true, /*NumChildren=*/1);
+  auto *Dir = new (Mem) OMPMetaDirective(NumVariants);
+  Dir->Data = Data;
   return Dir;
 }
 
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index fa9dac1d31af9..57298aae9f55e 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2686,8 +2686,9 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
         }
       }
 
-      // Skip Directive for now. We will parse directive in the second 
iteration
-     skipToMatchingParen();
+      // Skip Directive for now. We will parse directive in the second
+      // iteration.
+      skipToMatchingParen();
       if (Tok.is(tok::annot_pragma_openmp_end)) {
         Diag(Tok, diag::err_omp_expected_punc)
             << getOpenMPClauseName(CKind) << 0;
@@ -2722,20 +2723,21 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     // A single match is returned for OpenMP 5.0
     int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
 
-    // Check if we have any user conditions that need runtime or deferred
-    // evaluation:
-    // - Value-dependent conditions (template parameters): defer until
-    // instantiation.
-    // - Non-constant conditions (runtime variables): create runtime selection.
+    // Check if we have user conditions that are not simple IntegerLiterals.
+    // For simple IntegerLiterals (like condition(0) or condition(1)), we can
+    // evaluate them here. For anything else (variables, templates, complex
+    // expressions), we need to send to Sema for proper handling.
     bool HasNonConstantUserCondition = false;
     for (OMPTraitInfo *TI : TraitInfos) {
       if (TI && TI->hasUserCondition()) {
-        // Found a user condition - check if it's non-constant
+        // Check if all user conditions are simple IntegerLiterals.
         TI->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
-          if (!IsScore && E &&
-              (E->isValueDependent() || !E->isEvaluatable(ASTContext))) {
-            HasNonConstantUserCondition = true;
-            return true;
+          if (!IsScore && E) {
+            // If it's not a simple IntegerLiteral, we need Sema
+            if (!isa<IntegerLiteral>(E->IgnoreParenImpCasts())) {
+              HasNonConstantUserCondition = true;
+              return true;
+            }
           }
           return false;
         });
@@ -2743,10 +2745,53 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
           break;
       }
     }
-
-    // If we have non-constant conditions, collect all variants and send to 
Sema
-    // Sema handles both runtime selection and re-evaluation after template
-    // instantiation.
+    // For simple IntegerLiteral user conditions, re-evaluate BestIdx
+    // considering them. If the current BestIdx has a false user condition, 
find
+    // the next match.
+    if (!HasNonConstantUserCondition) {
+      // Helper to evaluate IntegerLiteral user conditions.
+      // All conditions were verified to be IntegerLiterals above.
+      auto evaluateUserCondition = [](OMPTraitInfo *TI) -> bool {
+        bool Result = true;
+        TI->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
+          if (!IsScore && E) {
+            if (auto *IL = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) 
{
+              Result = IL->getValue().getBoolValue();
+              return true;
+            }
+            llvm_unreachable("All user conditions verified as 
IntegerLiterals");
+          }
+          return false;
+        });
+        return Result;
+      };
+      if (BestIdx >= 0 && BestIdx < static_cast<int>(TraitInfos.size())) {
+        OMPTraitInfo *SelectedTI = TraitInfos[BestIdx];
+        if (SelectedTI && SelectedTI->hasUserCondition()) {
+          if (!evaluateUserCondition(SelectedTI)) {
+            // Current BestIdx has false condition, try to find next match.
+            BestIdx = -1;
+            for (int I = 0; I < static_cast<int>(VMIs.size()); ++I) {
+              if (I < static_cast<int>(TraitInfos.size())) {
+                OMPTraitInfo *TI = TraitInfos[I];
+                if (TI && TI->hasUserCondition()) {
+                  if (evaluateUserCondition(TI)) {
+                    BestIdx = I;
+                    break;
+                  }
+                } else {
+                  // No user condition or always-true context selector.
+                  BestIdx = I;
+                  break;
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    // If we have non-constant user conditions, collect all variants and send 
to
+    // Sema.
     if (HasNonConstantUserCondition) {
       // Collect all variants with their conditions.
       SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 7223c3d2904c0..15835af7545ce 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3796,6 +3796,7 @@ StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
     ArrayRef<Expr *> Conditions, ArrayRef<OpenMPDirectiveKind> DirectiveKinds,
     Stmt *AStmt, ArrayRef<Stmt *> VariantDirectives) {
 
+  assert(!TraitInfos.empty() && "TraitInfos should not be empty");
   assert(TraitInfos.size() == ClauseKinds.size() &&
          ClauseKinds.size() == Conditions.size() &&
          Conditions.size() == DirectiveKinds.size() &&
@@ -3804,9 +3805,6 @@ StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
           VariantDirectives.size() == DirectiveKinds.size()) &&
          "VariantDirectives, if provided, must match DirectiveKinds size");
 
-  if (TraitInfos.empty())
-    return StmtError();
-
   ASTContext &Context = getASTContext();
 
   // Check if all user conditions are constant.
@@ -3843,23 +3841,20 @@ StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
         if (SelectedKind == OMPD_unknown || SelectedKind == OMPD_nothing)
           return AStmt;
 
-        // Create the selected directive.
-        if (SelectedKind == OMPD_parallel) {
-          DeclarationNameInfo DirName;
-          DSAStack->push(OMPD_parallel, DirName, SemaRef.getCurScope(),
-                         StartLoc);
-          StmtResult ParallelStmt =
-              createParallelDirectiveForMetadirective(AStmt, StartLoc, EndLoc);
+        // Create the selected directive - need to create CapturedStmt first.
+        DeclarationNameInfo DirName;
+        DSAStack->push(SelectedKind, DirName, SemaRef.getCurScope(), StartLoc);
+        ActOnOpenMPRegionStart(SelectedKind, SemaRef.getCurScope());
+        StmtResult CapturedBody = ActOnOpenMPRegionEnd(AStmt, /*Clauses=*/{});
+        if (!CapturedBody.isUsable()) {
           DSAStack->pop();
-
-          if (ParallelStmt.isUsable())
-            return ParallelStmt;
           return StmtError();
-        } else {
-          // TODO: Handle other directive kinds
-          // For now, just return the statement
-          return AStmt;
         }
+        StmtResult DirectiveStmt = ActOnOpenMPExecutableDirective(
+            SelectedKind, DirName, /*CancelRegion=*/OMPD_unknown,
+            /*Clauses=*/{}, CapturedBody.get(), StartLoc, EndLoc);
+        DSAStack->pop();
+        return DirectiveStmt;
       }
     }
     return AStmt;
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index 59b08013e946e..edd98c9d0aaa5 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2516,9 +2516,9 @@ void 
ASTStmtReader::VisitOMPLoopDirective(OMPLoopDirective *D) {
 
 void ASTStmtReader::VisitOMPMetaDirective(OMPMetaDirective *D) {
   VisitStmt(D);
-  // The NumClauses field was read in ReadStmtFromStream.
-  Record.skipInts(1);
-  unsigned NumVariants = Record.readInt();
+  // The NumClauses and NumVariants fields were read in ReadStmtFromStream.
+  Record.skipInts(2);
+  unsigned NumVariants = D->getNumVariants();
   VisitOMPExecutableDirective(D);
 
   // Read directive kinds and conditions.
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp 
b/clang/lib/Serialization/ASTWriterStmt.cpp
index b9be4bafe7770..b1f972c4d7118 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2534,7 +2534,7 @@ void 
ASTStmtWriter::VisitOMPMetaDirective(OMPMetaDirective *D) {
   Record.push_back(D->getNumVariants());
   VisitOMPExecutableDirective(D);
   // Write directive kinds and conditions.
-   const OMPMetaDirective *ConstD = D;
+  const OMPMetaDirective *ConstD = D;
   for (auto DK : ConstD->getDirectiveKinds())
     Record.push_back(static_cast<unsigned>(DK));
 

>From 6a6cf37f1e4c289d39bb3f82c41c6c950bb89dc3 Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Fri, 17 Jul 2026 14:24:30 -0700
Subject: [PATCH 3/4] Changed raw pointers to Mutable

---
 clang/include/clang/AST/StmtOpenMP.h      | 63 +++++++++++++----------
 clang/lib/AST/StmtOpenMP.cpp              |  9 ++--
 clang/lib/Serialization/ASTReaderStmt.cpp |  4 +-
 3 files changed, 42 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index 5e9c6dacc31cd..7142fdde36ca5 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6417,41 +6417,53 @@ class OMPMetaDirective final : public 
OMPExecutableDirective {
   // Layout:
   // 
[OMPMetaDirective][DirectiveKinds...][padding][Conditions...][VariantDirectives...]
   // Each array is properly aligned for its element type.
-  OpenMPDirectiveKind *getTrailingDirectiveKinds() {
-    return reinterpret_cast<OpenMPDirectiveKind *>(this + 1);
+  MutableArrayRef<OpenMPDirectiveKind> getTrailingDirectiveKinds() {
+    return MutableArrayRef<OpenMPDirectiveKind>(
+        reinterpret_cast<OpenMPDirectiveKind *>(this + 1), NumVariants);
   }
 
-  const OpenMPDirectiveKind *getTrailingDirectiveKinds() const {
-    return reinterpret_cast<const OpenMPDirectiveKind *>(this + 1);
+  const ArrayRef<OpenMPDirectiveKind> getTrailingDirectiveKinds() const {
+    return ArrayRef<OpenMPDirectiveKind>(
+        reinterpret_cast<const OpenMPDirectiveKind *>(this + 1), NumVariants);
   }
 
-  Expr **getTrailingConditions() {
-    return reinterpret_cast<Expr **>(
-        reinterpret_cast<char *>(getTrailingDirectiveKinds()) +
-        offsetToConditions());
+  MutableArrayRef<Expr *> getTrailingConditions() {
+    return MutableArrayRef<Expr *>(
+        reinterpret_cast<Expr **>(reinterpret_cast<char *>(this + 1) +
+                                  offsetToConditions()),
+        NumVariants);
   }
 
-  const Expr *const *getTrailingConditions() const {
-    return reinterpret_cast<const Expr *const *>(
-        reinterpret_cast<const char *>(getTrailingDirectiveKinds()) +
-        offsetToConditions());
+  ArrayRef<Expr *> getTrailingConditions() const {
+    return ArrayRef<Expr *>(
+        reinterpret_cast<Expr *const *>(
+            reinterpret_cast<const char *>(this + 1) + offsetToConditions()),
+        NumVariants);
   }
 
-  Stmt **getTrailingVariantDirectives() {
-    return reinterpret_cast<Stmt **>(getTrailingConditions() + NumVariants);
+  MutableArrayRef<Stmt *> getTrailingVariantDirectives() {
+    auto Conditions = getTrailingConditions();
+    return MutableArrayRef<Stmt *>(
+        reinterpret_cast<Stmt **>(Conditions.data() + NumVariants),
+        NumVariants);
   }
 
-  const Stmt *const *getTrailingVariantDirectives() const {
-    return reinterpret_cast<const Stmt *const *>(getTrailingConditions() +
-                                                 NumVariants);
+  ArrayRef<Stmt *> getTrailingVariantDirectives() const {
+    auto Conditions = getTrailingConditions();
+    return ArrayRef<Stmt *>(
+        reinterpret_cast<Stmt *const *>(Conditions.data() + NumVariants),
+        NumVariants);
   }
 
-  OpenMPDirectiveKind *getDirectiveKinds() {
+  MutableArrayRef<OpenMPDirectiveKind> getDirectiveKinds() {
     return getTrailingDirectiveKinds();
   }
-  Expr **getConditions() { return getTrailingConditions(); }
 
-  Stmt **getVariantDirectives() { return getTrailingVariantDirectives(); }
+  MutableArrayRef<Expr *> getConditions() { return getTrailingConditions(); }
+
+  MutableArrayRef<Stmt *> getVariantDirectives() {
+    return getTrailingVariantDirectives();
+  }
 
 public:
   static OMPMetaDirective *
@@ -6466,18 +6478,13 @@ class OMPMetaDirective final : public 
OMPExecutableDirective {
   unsigned getNumVariants() const { return NumVariants; }
 
   ArrayRef<OpenMPDirectiveKind> getDirectiveKinds() const {
-    return ArrayRef<OpenMPDirectiveKind>(getTrailingDirectiveKinds(),
-                                         NumVariants);
+    return getTrailingDirectiveKinds();
   }
 
-  ArrayRef<Expr *> getConditions() const {
-    return ArrayRef<Expr *>(const_cast<Expr **>(getTrailingConditions()),
-                            NumVariants);
-  }
+  ArrayRef<Expr *> getConditions() const { return getTrailingConditions(); }
 
   ArrayRef<Stmt *> getVariantDirectives() const {
-    return ArrayRef<Stmt *>(const_cast<Stmt 
**>(getTrailingVariantDirectives()),
-                            NumVariants);
+    return getTrailingVariantDirectives();
   }
 
   child_range children() {
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index f055b9935e37e..b37dc5179fc27 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -300,15 +300,16 @@ OMPMetaDirective *OMPMetaDirective::Create(
   Dir->setIfStmt(IfStmt);
   if (NumVariants > 0) {
     std::copy(DirectiveKinds.begin(), DirectiveKinds.end(),
-              Dir->getDirectiveKinds());
-    std::copy(Conditions.begin(), Conditions.end(), Dir->getConditions());
+              Dir->getDirectiveKinds().begin());
+    std::copy(Conditions.begin(), Conditions.end(),
+              Dir->getConditions().begin());
 
     if (!VariantDirectives.empty())
       std::copy(VariantDirectives.begin(), VariantDirectives.end(),
-                Dir->getVariantDirectives());
+                Dir->getVariantDirectives().begin());
     else
       // Initialize VariantDirectives to nullptr.
-      std::fill_n(Dir->getVariantDirectives(), NumVariants, nullptr);
+      std::fill_n(Dir->getVariantDirectives().data(), NumVariants, nullptr);
   }
   return Dir;
 }
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp 
b/clang/lib/Serialization/ASTReaderStmt.cpp
index edd98c9d0aaa5..a38a809793244 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2527,13 +2527,13 @@ void 
ASTStmtReader::VisitOMPMetaDirective(OMPMetaDirective *D) {
     DirectiveKinds.push_back(
         static_cast<OpenMPDirectiveKind>(Record.readInt()));
   std::copy(DirectiveKinds.begin(), DirectiveKinds.end(),
-            D->getDirectiveKinds());
+            D->getDirectiveKinds().begin());
 
   for (unsigned I = 0; I < NumVariants; ++I)
     D->getConditions()[I] = Record.readSubExpr();
 
   // Read variant directives if present.
-  if (D->getVariantDirectives()) {
+  if (!D->getVariantDirectives().empty()) {
     for (unsigned I = 0; I < NumVariants; ++I)
       D->getVariantDirectives()[I] = Record.readSubStmt();
   }

>From 7c709ef21ce9f41f0dda0a16a63ad9834ca0dc6c Mon Sep 17 00:00:00 2001
From: Ammarguellat <[email protected]>
Date: Mon, 27 Jul 2026 06:42:12 -0700
Subject: [PATCH 4/4] Applied suggestions and removed sema analysis from parser

---
 clang/include/clang/AST/StmtOpenMP.h        |  2 +-
 clang/lib/Parse/ParseOpenMP.cpp             | 81 +++------------------
 clang/lib/Sema/SemaOpenMP.cpp               |  4 +-
 clang/test/OpenMP/metadirective_default.cpp | 66 ++++++++---------
 4 files changed, 45 insertions(+), 108 deletions(-)

diff --git a/clang/include/clang/AST/StmtOpenMP.h 
b/clang/include/clang/AST/StmtOpenMP.h
index 7142fdde36ca5..ae4aa12c21cbe 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6422,7 +6422,7 @@ class OMPMetaDirective final : public 
OMPExecutableDirective {
         reinterpret_cast<OpenMPDirectiveKind *>(this + 1), NumVariants);
   }
 
-  const ArrayRef<OpenMPDirectiveKind> getTrailingDirectiveKinds() const {
+  ArrayRef<OpenMPDirectiveKind> getTrailingDirectiveKinds() const {
     return ArrayRef<OpenMPDirectiveKind>(
         reinterpret_cast<const OpenMPDirectiveKind *>(this + 1), NumVariants);
   }
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp
index 57298aae9f55e..ace5e6d4c162b 100644
--- a/clang/lib/Parse/ParseOpenMP.cpp
+++ b/clang/lib/Parse/ParseOpenMP.cpp
@@ -2527,12 +2527,11 @@ StmtResult Parser::ParseOpenMPInformationalDirective(
       if (ConsumeDirectiveOnlyInMetadirective) {
         // Runtime path: stop at ')' - let the caller handle it.
         break;
-      } else {
-        // Compile-time path: consume everything to pragma end.
-        while (Tok.isNot(tok::annot_pragma_openmp_end))
-          ConsumeAnyToken();
-        break;
       }
+      // Compile-time path: consume everything to pragma end.
+      while (Tok.isNot(tok::annot_pragma_openmp_end))
+        ConsumeAnyToken();
+      break;
     }
 
     OpenMPClauseKind CKind = Tok.isAnnotation()
@@ -2723,76 +2722,16 @@ StmtResult 
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
     // A single match is returned for OpenMP 5.0
     int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
 
-    // Check if we have user conditions that are not simple IntegerLiterals.
-    // For simple IntegerLiterals (like condition(0) or condition(1)), we can
-    // evaluate them here. For anything else (variables, templates, complex
-    // expressions), we need to send to Sema for proper handling.
-    bool HasNonConstantUserCondition = false;
+    // Check if we have any user conditions.
+    bool HasUserCondition = false;
     for (OMPTraitInfo *TI : TraitInfos) {
       if (TI && TI->hasUserCondition()) {
-        // Check if all user conditions are simple IntegerLiterals.
-        TI->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
-          if (!IsScore && E) {
-            // If it's not a simple IntegerLiteral, we need Sema
-            if (!isa<IntegerLiteral>(E->IgnoreParenImpCasts())) {
-              HasNonConstantUserCondition = true;
-              return true;
-            }
-          }
-          return false;
-        });
-        if (HasNonConstantUserCondition)
-          break;
-      }
-    }
-    // For simple IntegerLiteral user conditions, re-evaluate BestIdx
-    // considering them. If the current BestIdx has a false user condition, 
find
-    // the next match.
-    if (!HasNonConstantUserCondition) {
-      // Helper to evaluate IntegerLiteral user conditions.
-      // All conditions were verified to be IntegerLiterals above.
-      auto evaluateUserCondition = [](OMPTraitInfo *TI) -> bool {
-        bool Result = true;
-        TI->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
-          if (!IsScore && E) {
-            if (auto *IL = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) 
{
-              Result = IL->getValue().getBoolValue();
-              return true;
-            }
-            llvm_unreachable("All user conditions verified as 
IntegerLiterals");
-          }
-          return false;
-        });
-        return Result;
-      };
-      if (BestIdx >= 0 && BestIdx < static_cast<int>(TraitInfos.size())) {
-        OMPTraitInfo *SelectedTI = TraitInfos[BestIdx];
-        if (SelectedTI && SelectedTI->hasUserCondition()) {
-          if (!evaluateUserCondition(SelectedTI)) {
-            // Current BestIdx has false condition, try to find next match.
-            BestIdx = -1;
-            for (int I = 0; I < static_cast<int>(VMIs.size()); ++I) {
-              if (I < static_cast<int>(TraitInfos.size())) {
-                OMPTraitInfo *TI = TraitInfos[I];
-                if (TI && TI->hasUserCondition()) {
-                  if (evaluateUserCondition(TI)) {
-                    BestIdx = I;
-                    break;
-                  }
-                } else {
-                  // No user condition or always-true context selector.
-                  BestIdx = I;
-                  break;
-                }
-              }
-            }
-          }
-        }
+        HasUserCondition = true;
+        break;
       }
     }
-    // If we have non-constant user conditions, collect all variants and send 
to
-    // Sema.
-    if (HasNonConstantUserCondition) {
+    // If we have user conditions, collect all variants.
+    if (HasUserCondition) {
       // Collect all variants with their conditions.
       SmallVector<OpenMPDirectiveKind, 4> DirectiveKinds;
       SmallVector<Expr *, 4> Conditions;
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 15835af7545ce..9f128dde374d4 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -3893,8 +3893,10 @@ StmtResult SemaOpenMP::ActOnOpenMPMetaDirective(
     if (ThenDK == OMPD_parallel) {
       StmtResult ParallelStmt =
           createParallelDirectiveForMetadirective(AStmt, StartLoc, EndLoc);
-      if (!ParallelStmt.isUsable())
+      if (!ParallelStmt.isUsable()) {
+        DSAStack->pop();
         return StmtError();
+      }
       ThenDirective = ParallelStmt.get();
       ThenStmt = ThenDirective;
     } else if (ThenDK == OMPD_unknown || ThenDK == OMPD_nothing) {
diff --git a/clang/test/OpenMP/metadirective_default.cpp 
b/clang/test/OpenMP/metadirective_default.cpp
index ab269f41b9380..25cfd9b88b8ce 100644
--- a/clang/test/OpenMP/metadirective_default.cpp
+++ b/clang/test/OpenMP/metadirective_default.cpp
@@ -39,7 +39,7 @@ void func1() {
 // CHECK-NEXT:    store i32 [[INC]], ptr [[I]], align 4
 // CHECK-NEXT:    br label %[[FOR_COND]], !llvm.loop [[LOOP3:![0-9]+]]
 // CHECK:       [[FOR_END]]:
-// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 
0, ptr @_Z5func1v.omp_outlined)
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr 
@[[GLOB1:[0-9]+]], i32 0, ptr @_Z5func1v.omp_outlined)
 // CHECK-NEXT:    ret void
 // CHECK-NEXT: }
 
@@ -49,24 +49,22 @@ void func1() {
 // CHECK-NEXT: entry
 // CHECK-NEXT:    [[GLOB_TID__ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    [[BOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK-NEXT:    [[OMP_IV:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[OMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[OMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[OMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT:    [[OMP_IS_LAST:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    [[I:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    store ptr [[DOTGLOBAL_TID_]], ptr [[GLOB_TID__ADDR]], align 8
 // CHECK-NEXT:    store ptr [[DOTBOUND_TID_]], ptr [[BOUND_TID__ADDR]], align 8
-// CHECK-NEXT:    store i32 0, ptr [[I]], align 4
-// CHECK-NEXT:    br label %for.cond
-// CHECK:for.cond:
-// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
-// CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[TMP0]], 100
-// CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
-// CHECK:for.body:
-// CHECK-NEXT:    br label [[FOR_INC:%.*]]
-// CHECK:for.inc:
-// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[I]], align 4
-// CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[TMP1]], 1
-// CHECK-NEXT:    store i32 [[INC]], ptr [[I]], align 4
-// CHECK-NEXT:    br label [[FOR_COND:%.*]]
-// CHECK:for.end:
-// CHECK-NEXT:  ret void
+// CHECK-NEXT:    store i32 0, ptr [[OMP_LB]], align 4
+// CHECK-NEXT:    store i32 99, ptr [[OMP_UB]], align 4
+// CHECK-NEXT:    store i32 1, ptr [[OMP_STRIDE]], align 4
+// CHECK-NEXT:    store i32 0, ptr [[OMP_IS_LAST]], align 4
+// CHECK:         call void @__kmpc_for_static_init_4(
+// CHECK:         call void @__kmpc_for_static_fini(
+// CHECK-NEXT:    ret void
 // CHECK-NEXT:}
 
 void func2() {
@@ -102,9 +100,9 @@ void func2() {
 // CHECK-NEXT:  store i32 99, ptr [[OMP_UB:%.*]], align 4
 // CHECK-NEXT:  store i32 1, ptr [[OMP_STRIDE:%.*]], align 4
 // CHECK-NEXT:  store i32 0, ptr [[OMP_IS_LAST:%.*]], align 4
-// CHECK-NEXT:  [[TID_PTR:%.*]] = load ptr, ptr [[GLOBAL_TID_ADDR:%.*]], align 
8
+// CHECK-NEXT:  [[TID_PTR:%.*]] = load ptr, ptr [[GLOB_TID__ADDR]], align 8
 // CHECK-NEXT:  [[TID_VAL:%.*]] = load i32, ptr [[TID_PTR]], align 4
-// CHECK-NEXT:  call void @__kmpc_for_static_init_4(ptr @2, i32 [[TID_VAL]], 
i32 34, ptr [[OMP_IS_LAST]], ptr [[OMP_LB]], ptr [[OMP_UB]], ptr 
[[OMP_STRIDE]], i32 1, i32 1)
+// CHECK-NEXT:  call void @__kmpc_for_static_init_4(ptr @[[GLOB_INIT:[0-9]+]], 
i32 [[TID_VAL]], i32 34, ptr [[OMP_IS_LAST]], ptr [[OMP_LB]], ptr [[OMP_UB]], 
ptr [[OMP_STRIDE]], i32 1, i32 1)
 // CHECK-NEXT:  [[UB_VAL:%.*]] = load i32, ptr [[OMP_UB]], align 4
 // CHECK-NEXT:  [[CMP:%.*]] = icmp sgt i32 [[UB_VAL]], 99
 // CHECK-NEXT:  br i1 [[CMP]], label [[COND_TRUE:%.*]], label 
[[COND_FALSE:%.*]]
@@ -148,7 +146,7 @@ void func2() {
 // CHECK-NEXT:  br label [[OMP_LOOP_EXIT:%.*]]
 
 // CHECK:omp.loop.exit:
-// CHECK-NEXT:  call void @__kmpc_for_static_fini(ptr @2, i32 [[TID:%.*]])
+// CHECK-NEXT:  call void @__kmpc_for_static_fini(ptr @[[GLOB_INIT]], i32 
[[TID_VAL]])
 // CHECK-NEXT:  ret void
 // CHECK-NEXT: }
 
@@ -165,7 +163,7 @@ void func3() {
 
 // CHECK-LABEL: define dso_local void @_Z5func3v()
 // CHECK:       entry
-// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @1, i32 
0, ptr @_Z5func3v.omp_outlined)
+// CHECK-NEXT:    call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr 
@[[GLOB3:[0-9]+]], i32 0, ptr @_Z5func3v.omp_outlined)
 // CHECK-NEXT:    ret void
 // CHECK-NEXT:   }
 
@@ -175,23 +173,21 @@ void func3() {
 // CHECK-NEXT:  entry
 // CHECK-NEXT:    [[GLOB_TID__ADDR:%.*]] = alloca ptr, align 8
 // CHECK-NEXT:    [[BOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK-NEXT:    [[I:%.*]] = alloca i32, align 4
+// CHECK:       [[OMP_IV:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[TMP:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[OMP_LB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[OMP_UB:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[OMP_STRIDE:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[OMP_IS_LAST:%.*]] = alloca i32, align 4
+// CHECK-NEXT:  [[I:%.*]] = alloca i32, align 4
 // CHECK-NEXT:    store ptr [[DOTGLOBAL_TID_]], ptr [[GLOB_TID__ADDR]], align 8
 // CHECK-NEXT:    store ptr [[DOTBOUND_TID_]], ptr [[BOUND_TID__ADDR]], align 8
-// CHECK-NEXT:    store i32 0, ptr [[I]], align 4
-// CHECK-NEXT:    br label %for.cond
-// CHECK:for.cond:
-// CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr [[I]], align 4
-// CHECK-NEXT:    [[CMP:%.*]] = icmp slt i32 [[TMP0]], 100
-// CHECK-NEXT:    br i1 [[CMP]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
-// CHECK:for.body:
-// CHECK-NEXT:    br label [[FOR_INC:%.*]]
-// CHECK:for.inc:
-// CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr [[I]], align 4
-// CHECK-NEXT:    [[INC:%.*]] = add nsw i32 [[TMP1]], 1
-// CHECK-NEXT:    store i32 [[INC]], ptr [[I]], align 4
-// CHECK-NEXT:    br label [[FOR_COND:%.*]]
-// CHECK:for.end:
+// CHECK:       store i32 0, ptr [[OMP_LB]], align 4
+// CHECK-NEXT:  store i32 99, ptr [[OMP_UB]], align 4
+// CHECK-NEXT:  store i32 1, ptr [[OMP_STRIDE]], align 4
+// CHECK-NEXT:  store i32 0, ptr [[OMP_IS_LAST]], align 4
+// CHECK:       call void @__kmpc_for_static_init_4(
+// CHECK:       call void @__kmpc_for_static_fini(
 // CHECK-NEXT:  ret void
 // CHECK-NEXT:}
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to