alokmishra.besu updated this revision to Diff 309268.
alokmishra.besu added a comment.

Updated version of metadirective supporting OpenMP 5.0 features


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D91944/new/

https://reviews.llvm.org/D91944

Files:
  clang/include/clang-c/Index.h
  clang/include/clang/AST/RecursiveASTVisitor.h
  clang/include/clang/AST/StmtOpenMP.h
  clang/include/clang/Basic/DiagnosticParseKinds.td
  clang/include/clang/Basic/StmtNodes.td
  clang/include/clang/Sema/Sema.h
  clang/include/clang/Serialization/ASTBitCodes.h
  clang/lib/AST/OpenMPClause.cpp
  clang/lib/AST/StmtOpenMP.cpp
  clang/lib/AST/StmtPrinter.cpp
  clang/lib/AST/StmtProfile.cpp
  clang/lib/Basic/OpenMPKinds.cpp
  clang/lib/CodeGen/CGOpenMPRuntime.cpp
  clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
  clang/lib/CodeGen/CGStmt.cpp
  clang/lib/CodeGen/CGStmtOpenMP.cpp
  clang/lib/CodeGen/CodeGenFunction.h
  clang/lib/Parse/ParseOpenMP.cpp
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaOpenMP.cpp
  clang/lib/Sema/TreeTransform.h
  clang/lib/Serialization/ASTReaderStmt.cpp
  clang/lib/Serialization/ASTWriterStmt.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
  clang/test/OpenMP/metadirective_ast_print.c
  clang/test/OpenMP/metadirective_ast_print.cpp
  clang/test/OpenMP/metadirective_device_kind_codegen.c
  clang/test/OpenMP/metadirective_device_kind_codegen.cpp
  clang/test/OpenMP/metadirective_empty.cpp
  clang/test/OpenMP/metadirective_implementation_codegen.c
  clang/test/OpenMP/metadirective_implementation_codegen.cpp
  clang/test/OpenMP/metadirective_messages.cpp
  clang/tools/libclang/CIndex.cpp
  clang/tools/libclang/CXCursor.cpp
  llvm/include/llvm/Frontend/OpenMP/OMP.td
  llvm/include/llvm/Frontend/OpenMP/OMPContext.h
  llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
  llvm/lib/Frontend/OpenMP/OMPContext.cpp

Index: llvm/lib/Frontend/OpenMP/OMPContext.cpp
===================================================================
--- llvm/lib/Frontend/OpenMP/OMPContext.cpp
+++ llvm/lib/Frontend/OpenMP/OMPContext.cpp
@@ -332,6 +332,16 @@
   return Score;
 }
 
+int llvm::omp::getBestWhenMatchForContext(
+    const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx,
+    SmallVectorImpl<unsigned> *OrderedMatch) {
+
+  // TODO: This will become invalid in OpenMP 5.1
+  // In OpenMP 5.1 we need to analyze and get all variant which can be resolved
+  // during runtime, and set their position in OrderedMatch.
+  return getBestVariantMatchForContext(VMIs, Ctx);
+}
+
 int llvm::omp::getBestVariantMatchForContext(
     const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx) {
 
Index: llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
===================================================================
--- llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
+++ llvm/include/llvm/Frontend/OpenMP/OMPKinds.def
@@ -115,6 +115,7 @@
 __OMP_CLAUSE_NO_CLASS(uniform)
 __OMP_CLAUSE_NO_CLASS(device_type)
 __OMP_CLAUSE_NO_CLASS(match)
+__OMP_CLAUSE_NO_CLASS(when)
 
 __OMP_IMPLICIT_CLAUSE_CLASS(depobj, "depobj", OMPDepobjClause)
 __OMP_IMPLICIT_CLAUSE_CLASS(flush, "flush", OMPFlushClause)
Index: llvm/include/llvm/Frontend/OpenMP/OMPContext.h
===================================================================
--- llvm/include/llvm/Frontend/OpenMP/OMPContext.h
+++ llvm/include/llvm/Frontend/OpenMP/OMPContext.h
@@ -184,6 +184,13 @@
                                   const OMPContext &Ctx,
                                   bool DeviceSetOnly = false);
 
+/// Return the index (into \p VMIs) of the When clause with the highest score
+/// from the ones applicble in \p Ctx.
+/// In OpenMP 5.1 set OrderedMatch to those conditions which need runtime
+/// resolution.
+int getBestWhenMatchForContext(
+    const SmallVectorImpl<VariantMatchInfo> &VMIs, const OMPContext &Ctx,
+    SmallVectorImpl<unsigned> *OrderedMatch = nullptr);
 /// Return the index (into \p VMIs) of the variant with the highest score
 /// from the ones applicble in \p Ctx. See llvm::isVariantApplicableInContext.
 int getBestVariantMatchForContext(const SmallVectorImpl<VariantMatchInfo> &VMIs,
Index: llvm/include/llvm/Frontend/OpenMP/OMP.td
===================================================================
--- llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -59,6 +59,7 @@
   let clangClass = "OMPCollapseClause";
   let flangClassValue = "ScalarIntConstantExpr";
 }
+def OMPC_When: Clause<"when"> {}
 def OMPC_Default : Clause<"default"> {
   let clangClass = "OMPDefaultClause";
   let flangClass = "OmpDefaultClause";
@@ -295,6 +296,14 @@
 // Definition of OpenMP directives
 //===----------------------------------------------------------------------===//
 
+def OMP_Metadirective : Directive<"metadirective"> {
+  let allowedClauses = [
+    VersionedClause<OMPC_When>
+  ];
+  let allowedOnceClauses = [
+    VersionedClause<OMPC_Default>
+  ];
+}
 def OMP_ThreadPrivate : Directive<"threadprivate"> {}
 def OMP_Parallel : Directive<"parallel"> {
   let allowedClauses = [
Index: clang/tools/libclang/CXCursor.cpp
===================================================================
--- clang/tools/libclang/CXCursor.cpp
+++ clang/tools/libclang/CXCursor.cpp
@@ -639,6 +639,9 @@
   case Stmt::MSDependentExistsStmtClass:
     K = CXCursor_UnexposedStmt;
     break;
+  case Stmt::OMPMetaDirectiveClass:
+    K = CXCursor_OMPMetaDirective;
+    break;
   case Stmt::OMPParallelDirectiveClass:
     K = CXCursor_OMPParallelDirective;
     break;
Index: clang/tools/libclang/CIndex.cpp
===================================================================
--- clang/tools/libclang/CIndex.cpp
+++ clang/tools/libclang/CIndex.cpp
@@ -5525,6 +5525,8 @@
     return cxstring::createRef("CXXAccessSpecifier");
   case CXCursor_ModuleImportDecl:
     return cxstring::createRef("ModuleImport");
+  case CXCursor_OMPMetaDirective:
+    return cxstring::createRef("OMPMetaDirective");
   case CXCursor_OMPParallelDirective:
     return cxstring::createRef("OMPParallelDirective");
   case CXCursor_OMPSimdDirective:
Index: clang/test/OpenMP/metadirective_messages.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_messages.cpp
@@ -0,0 +1,18 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -emit-llvm %s
+
+void foo() {
+#pragma omp metadirective // expected-error {{expected expression}}
+  ;
+#pragma omp metadirective when() // expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}} expected-warning {{expected identifier or string literal describing a context set; set skipped}} expected-note {{context set options are: 'construct' 'device' 'implementation' 'user'}} expected-note {{the ignored set spans until here}}
+  ;
+#pragma omp metadirective when(device{}) // expected-error {{expected valid context selector in when clause}} expected-error {{expected expression}} expected-warning {{expected '=' after the context set name "device"; '=' assumed}} expected-warning {{expected identifier or string literal describing a context selector; selector skipped}} expected-note {{context selector options are: 'kind' 'isa' 'arch'}} expected-note {{the ignored selector spans until here}}
+  ;
+#pragma omp metadirective when(device{arch(nvptx)}) // expected-error {{missing ':' in when clause}} expected-error {{expected expression}} expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
+  ;
+#pragma omp metadirective when(device{arch(nvptx)} \
+                               :) default() // expected-warning {{expected '=' after the context set name "device"; '=' assumed}}
+  ;
+#pragma omp metadirective when(device = {arch(nvptx)} \
+                               :) default(xyz) // expected-error {{expected an OpenMP directive}}
+  ;
+}
Index: clang/test/OpenMP/metadirective_implementation_codegen.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_implementation_codegen.cpp
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple aarch64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple ppc64le-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+void bar();
+
+void foo() {
+#pragma omp metadirective when(implementation = {vendor(score(0)  \
+                                                        : llvm)}, \
+                               device = {kind(cpu)}               \
+                               : parallel) default(target teams)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)}                                 \
+                               : target teams) when(implementation = {vendor(llvm)} \
+                                                    : parallel) default()
+  bar();
+#pragma omp metadirective default(target) when(implementation = {vendor(score(5)  \
+                                                                        : llvm)}, \
+                                               device = {kind(cpu, host)}         \
+                                               : parallel)
+  bar();
+#pragma omp metadirective when(implementation = {extension(match_all)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_any)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_none)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: define void @_Z3foov()
+// CHECK-COUNT-6: ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined.(
+// CHECK: @_Z3barv
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..1(
+// CHECK: @_Z3barv
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..2(
+// CHECK: @_Z3barv
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..3(
+// NO-CHECK: call void @__kmpc_for_static_init
+// NO-CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..4(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..5(
+// NO-CHECK: call void @__kmpc_for_static_init
+// NO-CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
Index: clang/test/OpenMP/metadirective_implementation_codegen.c
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_implementation_codegen.c
@@ -0,0 +1,67 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple aarch64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple ppc64le-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+void bar();
+
+void foo() {
+#pragma omp metadirective when(implementation = {vendor(score(0)  \
+                                                        : llvm)}, \
+                               device = {kind(cpu)}               \
+                               : parallel) default(target teams)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)}                                 \
+                               : target teams) when(implementation = {vendor(llvm)} \
+                                                    : parallel) default()
+  bar();
+#pragma omp metadirective default(target) when(implementation = {vendor(score(5)  \
+                                                                        : llvm)}, \
+                                               device = {kind(cpu, host)}         \
+                                               : parallel)
+  bar();
+#pragma omp metadirective when(implementation = {extension(match_all)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_any)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_none)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: define void @foo()
+// CHECK-COUNT-6: ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined.(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..1(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..2(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..3(
+// NO-CHECK: call void @__kmpc_for_static_init
+// NO-CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..4(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..5(
+// NO-CHECK: call void @__kmpc_for_static_init
+// NO-CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
Index: clang/test/OpenMP/metadirective_empty.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_empty.cpp
@@ -0,0 +1,31 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+#define N 1000
+void func() {
+  // Test where a valid when clause contains empty directive.
+  // The directive will be ignored and code for a serial for loop will be generated.
+#pragma omp metadirective when(implementation = {vendor(llvm)} \
+                               :) default(parallel for)
+  for (int i = 0; i < N; i++)
+    ;
+}
+
+// CHECK: define void @_Z4funcv() #0 {
+// CHECK: entry:
+// CHECK:   %i = alloca i32, align 4
+// CHECK:   store i32 0, i32* %i, align 4
+// CHECK:   br label %for.cond
+// CHECK: for.cond:
+// CHECK:   %0 = load i32, i32* %i, align 4
+// CHECK:   %cmp = icmp slt i32 %0, 1000
+// CHECK:   br i1 %cmp, label %for.body, label %for.end
+// CHECK: for.body:
+// CHECK:   br label %for.inc
+// CHECK: for.inc:
+// CHECK:   %1 = load i32, i32* %i, align 4
+// CHECK:   %inc = add nsw i32 %1, 1
+// CHECK:   store i32 %inc, i32* %i, align 4
+// CHECK:   br label %for.cond, !llvm.loop !2
+// CHECK: for.end:
+// CHECK:   ret void
+// CHECK: }
Index: clang/test/OpenMP/metadirective_device_kind_codegen.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_device_kind_codegen.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple aarch64-unknown-linux -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple ppc64le-unknown-linux -emit-llvm %s -fexceptions -fcxx-exceptions -o - -fsanitize-address-use-after-scope | FileCheck %s
+
+// expected-no-diagnostics
+
+void bar();
+
+void foo() {
+#pragma omp metadirective when(device = {kind(any)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(host, cpu)} \
+                               : parallel for num_threads(4))
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(device = {kind(host)} \
+                               : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(device = {kind(nohost, gpu)} \
+                               :) when(device = {kind(cpu)} \
+                                       : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(any, cpu)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(any, host)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)} \
+                               : target parallel for) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: define void @_Z3foov()
+// CHECK: ...) @__kmpc_fork_call(
+// CHECK-NEXT: @__kmpc_push_num_threads
+// CHECK-COUNT-6: ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined.(
+// CHECK: void @_Z3barv()
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..1(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..2(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..3(
+// CHECK: void @_Z3barv()
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..4(
+// CHECK: void @_Z3barv()
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..5(
+// CHECK: void @_Z3barv()
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..6(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
Index: clang/test/OpenMP/metadirective_device_kind_codegen.c
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_device_kind_codegen.c
@@ -0,0 +1,72 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple x86_64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple aarch64-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// RUN: %clang_cc1 -verify -fopenmp -x c -triple ppc64le-unknown-linux -emit-llvm %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+void bar();
+
+void foo() {
+#pragma omp metadirective when(device = {kind(any)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(host, cpu)} \
+                               : parallel for num_threads(4))
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(device = {kind(host)} \
+                               : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(device = {kind(nohost, gpu)} \
+                               :) when(device = {kind(cpu)} \
+                                       : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(any, cpu)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(any, host)} \
+                               : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)} \
+                               : target parallel for) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: define void @foo()
+// CHECK: ...) @__kmpc_fork_call(
+// CHECK-NEXT: @__kmpc_push_num_threads
+// CHECK-COUNT-6: ...) @__kmpc_fork_call(
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined.(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..1(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..2(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..3(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..4(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..5(
+// CHECK: @bar
+// CHECK: ret void
+
+// CHECK: define internal void @.omp_outlined..6(
+// CHECK: call void @__kmpc_for_static_init
+// CHECK: call void @__kmpc_for_static_fini
+// CHECK: ret void
Index: clang/test/OpenMP/metadirective_ast_print.cpp
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_ast_print.cpp
@@ -0,0 +1,73 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c++ -std=c++14 -ast-print %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+void bar(void);
+
+#define ISTRUE true
+#define ISFALSE false
+void foo(void) {
+#pragma omp metadirective when(device = {kind(cpu)} \
+                               : parallel) default()
+  bar();
+#pragma omp metadirective when(implementation = {vendor(score(0)  \
+                                                        : llvm)}, \
+                               device = {kind(cpu)}               \
+                               : parallel) default(target teams)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)}                                 \
+                               : target teams) when(implementation = {vendor(llvm)} \
+                                                    : parallel) default()
+  bar();
+#pragma omp metadirective default(target) when(implementation = {vendor(score(5)  \
+                                                                        : llvm)}, \
+                                               device = {kind(cpu, host)}         \
+                                               : parallel)
+  bar();
+#pragma omp metadirective when(user = {condition(false)}               \
+                               : target) when(user = {condition(true)} \
+                                              : parallel)
+  bar();
+#pragma omp metadirective when(user = {condition(ISTRUE)}                   \
+                               : parallel) when(user = {condition(ISFALSE)} \
+                                                :)
+  bar();
+#pragma omp metadirective when(device = {kind(host)} \
+                               : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_all)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_any)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_none)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: void bar();
+// CHECK: void foo()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel for
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel for
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
Index: clang/test/OpenMP/metadirective_ast_print.c
===================================================================
--- /dev/null
+++ clang/test/OpenMP/metadirective_ast_print.c
@@ -0,0 +1,66 @@
+// RUN: %clang_cc1 -verify -fopenmp -x c -std=c99 -ast-print %s -o - | FileCheck %s
+// expected-no-diagnostics
+
+void bar(void);
+
+#define N 10
+void foo(void) {
+#pragma omp metadirective when(device = {kind(cpu)} \
+                               : parallel) default()
+  bar();
+#pragma omp metadirective when(implementation = {vendor(score(0)  \
+                                                        : llvm)}, \
+                               device = {kind(cpu)}               \
+                               : parallel) default(target teams)
+  bar();
+#pragma omp metadirective when(device = {kind(gpu)}                                 \
+                               : target teams) when(implementation = {vendor(llvm)} \
+                                                    : parallel) default()
+  bar();
+#pragma omp metadirective default(target) when(implementation = {vendor(score(5)  \
+                                                                        : llvm)}, \
+                                               device = {kind(cpu, host)}         \
+                                               : parallel)
+  bar();
+#pragma omp metadirective when(user = {condition(N > 10)}                 \
+                               : target) when(user = {condition(N == 10)} \
+                                              : parallel)
+  bar();
+#pragma omp metadirective when(device = {kind(host)} \
+                               : parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_all)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_any)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+#pragma omp metadirective when(implementation = {extension(match_none)} \
+                               : parallel) default(parallel for)
+  for (int i = 0; i < 100; i++)
+    ;
+}
+
+// CHECK: void bar();
+// CHECK: void foo()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel
+// CHECK-NEXT: bar()
+// CHECK-NEXT: #pragma omp parallel for
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel for
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
+// CHECK: #pragma omp parallel
+// CHECK-NEXT: for (int i = 0; i < 100; i++)
Index: clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -1292,6 +1292,7 @@
     case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
     case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
     case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
+    case Stmt::OMPMetaDirectiveClass:
     case Stmt::CapturedStmtClass: {
       const ExplodedNode *node = Bldr.generateSink(S, Pred, Pred->getState());
       Engine.addAbortedBlock(node, currBldrCtx->getBlock());
Index: clang/lib/Serialization/ASTWriterStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTWriterStmt.cpp
+++ clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2176,6 +2176,13 @@
   Record.AddSourceLocation(E->getEndLoc());
 }
 
+void ASTStmtWriter::VisitOMPMetaDirective(OMPMetaDirective *D) {
+  VisitStmt(D);
+  Record.push_back(D->getNumClauses());
+  VisitOMPExecutableDirective(D);
+  Code = serialization::STMT_OMP_META_DIRECTIVE;
+}
+
 void ASTStmtWriter::VisitOMPLoopDirective(OMPLoopDirective *D) {
   VisitStmt(D);
   Record.writeUInt32(D->getCollapsedNumber());
Index: clang/lib/Serialization/ASTReaderStmt.cpp
===================================================================
--- clang/lib/Serialization/ASTReaderStmt.cpp
+++ clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2286,6 +2286,13 @@
   VisitOMPExecutableDirective(D);
 }
 
+void ASTStmtReader::VisitOMPMetaDirective(OMPMetaDirective *D) {
+  VisitStmt(D);
+  // The NumClauses field was read in ReadStmtFromStream.
+  Record.skipInts(1);
+  VisitOMPExecutableDirective(D);
+}
+
 void ASTStmtReader::VisitOMPParallelDirective(OMPParallelDirective *D) {
   VisitStmt(D);
   VisitOMPExecutableDirective(D);
@@ -3130,6 +3137,11 @@
                                               nullptr);
       break;
 
+    case STMT_OMP_META_DIRECTIVE:
+      S = OMPMetaDirective::CreateEmpty(
+          Context, Record[ASTStmtReader::NumStmtFields], Empty);
+      break;
+
     case STMT_OMP_PARALLEL_DIRECTIVE:
       S =
         OMPParallelDirective::CreateEmpty(Context,
Index: clang/lib/Sema/TreeTransform.h
===================================================================
--- clang/lib/Sema/TreeTransform.h
+++ clang/lib/Sema/TreeTransform.h
@@ -8379,6 +8379,17 @@
 
 template <typename Derived>
 StmtResult
+TreeTransform<Derived>::TransformOMPMetaDirective(OMPMetaDirective *D) {
+  DeclarationNameInfo DirName;
+  getDerived().getSema().StartOpenMPDSABlock(OMPD_metadirective, DirName,
+                                             nullptr, D->getBeginLoc());
+  StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+  getDerived().getSema().EndOpenMPDSABlock(Res.get());
+  return Res;
+}
+
+template <typename Derived>
+StmtResult
 TreeTransform<Derived>::TransformOMPParallelDirective(OMPParallelDirective *D) {
   DeclarationNameInfo DirName;
   getDerived().getSema().StartOpenMPDSABlock(OMPD_parallel, DirName, nullptr,
Index: clang/lib/Sema/SemaOpenMP.cpp
===================================================================
--- clang/lib/Sema/SemaOpenMP.cpp
+++ clang/lib/Sema/SemaOpenMP.cpp
@@ -3749,6 +3749,7 @@
 
 void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
   switch (DKind) {
+  case OMPD_metadirective:
   case OMPD_parallel:
   case OMPD_parallel_for:
   case OMPD_parallel_for_simd:
@@ -5434,6 +5435,7 @@
     if (LangOpts.OpenMP >= 50)
       AllowedNameModifiers.push_back(OMPD_simd);
     break;
+  case OMPD_metadirective:
   case OMPD_declare_target:
   case OMPD_end_declare_target:
   case OMPD_threadprivate:
@@ -5552,6 +5554,7 @@
       case OMPC_atomic_default_mem_order:
       case OMPC_device_type:
       case OMPC_match:
+      case OMPC_when:
       default:
         llvm_unreachable("Unexpected clause");
       }
@@ -11855,6 +11858,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -12008,6 +12012,7 @@
     case OMPD_atomic:
     case OMPD_teams_distribute:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with if-clause");
     case OMPD_unknown:
     default:
@@ -12087,6 +12092,7 @@
     case OMPD_teams_distribute:
     case OMPD_teams_distribute_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with num_threads-clause");
     case OMPD_unknown:
     default:
@@ -12164,6 +12170,7 @@
     case OMPD_atomic:
     case OMPD_distribute_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
     case OMPD_unknown:
     default:
@@ -12241,6 +12248,7 @@
     case OMPD_atomic:
     case OMPD_distribute_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause");
     case OMPD_unknown:
     default:
@@ -12318,6 +12326,7 @@
     case OMPD_distribute_simd:
     case OMPD_target_teams:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with schedule clause");
     case OMPD_unknown:
     default:
@@ -12395,6 +12404,7 @@
     case OMPD_atomic:
     case OMPD_target_teams:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with schedule clause");
     case OMPD_unknown:
     default:
@@ -12472,6 +12482,7 @@
     case OMPD_atomic:
     case OMPD_distribute_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with num_teams-clause");
     case OMPD_unknown:
     default:
@@ -12551,12 +12562,22 @@
     case OMPD_atomic:
     case OMPD_distribute_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
       llvm_unreachable("Unexpected OpenMP directive with grainsize-clause");
     case OMPD_unknown:
     default:
       llvm_unreachable("Unknown OpenMP directive");
     }
     break;
+  case OMPC_when:
+    if (DKind == OMPD_metadirective) {
+      CaptureRegion = OMPD_metadirective;
+    } else if (DKind == OMPD_unknown) {
+      llvm_unreachable("Unknown OpenMP directive");
+    } else {
+      llvm_unreachable("Unexpected OpenMP directive with when clause");
+    }
+    break;
   case OMPC_firstprivate:
   case OMPC_lastprivate:
   case OMPC_reduction:
@@ -13064,6 +13085,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -13303,6 +13325,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -13541,6 +13564,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed.");
   }
@@ -13819,6 +13843,7 @@
   case OMPC_destroy:
   case OMPC_detach:
   case OMPC_uses_allocators:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed.");
   }
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -1484,6 +1484,7 @@
   case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
   case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
   case Stmt::OMPTeamsDistributeSimdDirectiveClass:
+  case Stmt::OMPMetaDirectiveClass:
   case Stmt::ReturnStmtClass:
   case Stmt::SEHExceptStmtClass:
   case Stmt::SEHFinallyStmtClass:
Index: clang/lib/Parse/ParseOpenMP.cpp
===================================================================
--- clang/lib/Parse/ParseOpenMP.cpp
+++ clang/lib/Parse/ParseOpenMP.cpp
@@ -2086,6 +2086,7 @@
   case OMPD_target_teams_distribute_parallel_for:
   case OMPD_target_teams_distribute_parallel_for_simd:
   case OMPD_target_teams_distribute_simd:
+  case OMPD_metadirective:
     Diag(Tok, diag::err_omp_unexpected_directive)
         << 1 << getOpenMPDirectiveName(DKind);
     break;
@@ -2158,6 +2159,192 @@
   bool HasAssociatedStatement = true;
 
   switch (DKind) {
+  case OMPD_metadirective: {
+    ConsumeToken();
+    SmallVector<VariantMatchInfo, 4> VMIs;
+    OpenMPDirectiveKind DirKind = OMPD_unknown;
+    StmtResult AssociatedStmt;
+
+    // First iteration of parsing all clauses of metadirective.
+    // This iteration only parses and collects all context selector ignoring the
+    // assiciated directives.
+    TentativeParsingAction TPA(*this);
+    ASTContext &ASTContext = Actions.getASTContext();
+
+    BalancedDelimiterTracker T(*this, tok::l_paren,
+                               tok::annot_pragma_openmp_end);
+    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      OpenMPClauseKind CKind = Tok.isAnnotation()
+                                   ? OMPC_unknown
+                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
+      SourceLocation Loc = ConsumeToken();
+
+      // Parse '('.
+      if (T.expectAndConsume(diag::err_expected_lparen_after,
+                             getOpenMPClauseName(CKind).data()))
+        return Directive;
+
+      OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+      if (CKind == OMPC_when) {
+        // parse and get OMPTraitInfo to pass to the When clause
+        parseOMPContextSelectors(Loc, TI);
+        if (TI.Sets.size() == 0) {
+          Diag(Tok, diag::err_omp_expected_context_selector) << "when clause";
+          return Directive;
+        }
+
+        // Parse ':'
+        if (Tok.is(tok::colon))
+          ConsumeAnyToken();
+        else {
+          Diag(Tok, diag::err_omp_expected_colon) << "when clause";
+          return Directive;
+        }
+      }
+      // 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;
+          return Directive;
+        }
+        ConsumeAnyToken();
+      }
+      // Parse ')'
+      if (Tok.is(tok::r_paren))
+        T.consumeClose();
+
+      VariantMatchInfo VMI;
+      TI.getAsVariantMatchInfo(ASTContext, VMI);
+
+      VMIs.push_back(VMI);
+    }
+
+    TPA.Revert();
+    // End of the first iteration. Parser is reset to the start of metadirective
+
+    TargetOMPContext OMPCtx(ASTContext, nullptr, nullptr);
+
+    // A single match is returned for OpenMP 5.0
+    // TODO: Pass a list to getBestWhenMatchForContext to get an ordered match
+    // of those conditions which need runtime resolution in OpenMP 5.1
+    int BestIdx = getBestWhenMatchForContext(VMIs, OMPCtx);
+
+    int idx = 0;
+    // In OpenMP 5.0 metadirective is either replaced by another directive or
+    // ignored.
+    // TODO: In OpenMP 5.1 generate multiple directives based upon the matches
+    // found by getBestWhenMatchForContext.
+    while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+      // OpenMP 5.0 implementation - Skip to the best index found.
+      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();
+        }
+        // Parse ')'
+        if (Tok.is(tok::r_paren))
+          T.consumeClose();
+        continue;
+      }
+
+      OpenMPClauseKind CKind = Tok.isAnnotation()
+                                   ? OMPC_unknown
+                                   : getOpenMPClauseKind(PP.getSpelling(Tok));
+      SourceLocation Loc = ConsumeToken();
+
+      // Parse '('.
+      T.consumeOpen();
+
+      // Skip ContextSelectors for when clause
+      if (CKind == OMPC_when) {
+        OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+        // parse and skip the ContextSelectors
+        parseOMPContextSelectors(Loc, TI);
+
+        // Parse ':'
+        ConsumeAnyToken();
+      }
+
+      // If no directive is passed, skip in OpenMP 5.0.
+      // TODO: Generate nothing directive from OpenMP 5.1.
+      if (Tok.is(tok::r_paren)) {
+        SkipUntil(tok::annot_pragma_openmp_end);
+        break;
+      }
+
+      // Parse Directive
+      DirKind = parseOpenMPDirectiveKind(*this);
+      ConsumeToken();
+      if (DirKind == OMPD_unknown) {
+        // Unknown Directive encountered, generate error.
+        Diag(Tok, diag::err_omp_unknown_directive);
+        SkipUntil(tok::annot_pragma_openmp_end);
+        break;
+      }
+
+      ParseScope OMPDirectiveScope(this, ScopeFlags);
+      Actions.StartOpenMPDSABlock(DirKind, DirName, Actions.getCurScope(), Loc);
+      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--;
+        OpenMPClauseKind CKind = Tok.isAnnotation()
+                                     ? OMPC_unknown
+                                     : getOpenMPClauseKind(PP.getSpelling(Tok));
+        Actions.StartOpenMPClause(CKind);
+        OMPClause *DClause = ParseOpenMPClause(
+            DirKind, CKind, !FirstClauses[(unsigned)CKind].getInt());
+        FirstClauses[(unsigned)CKind].setInt(true);
+        if (DClause) {
+          FirstClauses[(unsigned)CKind].setPointer(DClause);
+          Clauses.push_back(DClause);
+        }
+        // Skip ',' if any.
+        if (Tok.is(tok::comma))
+          ConsumeToken();
+        Actions.EndOpenMPClause();
+      }
+      // TODO: In OpenMP 5.1 do not skip till end of pragma as other clause
+      // need to be considered for runtime code generation.
+      SkipUntil(tok::annot_pragma_openmp_end);
+
+      // End location of the directive.
+      EndLoc = Tok.getLocation();
+
+      Actions.ActOnOpenMPRegionStart(DirKind, getCurScope());
+      ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
+      ParseScope InnerStmtScope(this, Scope::DeclScope,
+                                getLangOpts().C99 || getLangOpts().CPlusPlus,
+                                Tok.is(tok::l_brace));
+      StmtResult AStmt = ParseStatement();
+      InnerStmtScope.Exit();
+      AssociatedStmt = (Sema::CompoundScopeRAII(Actions), AStmt);
+      AssociatedStmt = Actions.ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
+      Directive = Actions.ActOnOpenMPExecutableDirective(
+          DirKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc,
+          EndLoc);
+      // Exit scope.
+      Actions.EndOpenMPDSABlock(Directive.get());
+      OMPDirectiveScope.Exit();
+      break;
+    }
+    break;
+  }
   case OMPD_threadprivate: {
     // FIXME: Should this be permitted in C++?
     if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) ==
@@ -2760,6 +2947,7 @@
   case OMPC_threadprivate:
   case OMPC_uniform:
   case OMPC_match:
+  case OMPC_when:
     if (!WrongDirective)
       Diag(Tok, diag::err_omp_unexpected_clause)
           << getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
Index: clang/lib/CodeGen/CodeGenFunction.h
===================================================================
--- clang/lib/CodeGen/CodeGenFunction.h
+++ clang/lib/CodeGen/CodeGenFunction.h
@@ -3383,6 +3383,7 @@
                                        const RegionCodeGenTy &BodyGen,
                                        OMPTargetDataInfo &InputInfo);
 
+  void EmitOMPMetaDirective(const OMPMetaDirective &S);
   void EmitOMPParallelDirective(const OMPParallelDirective &S);
   void EmitOMPSimdDirective(const OMPSimdDirective &S);
   void EmitOMPForDirective(const OMPForDirective &S);
Index: clang/lib/CodeGen/CGStmtOpenMP.cpp
===================================================================
--- clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -5399,6 +5399,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
   default:
     llvm_unreachable("Clause is not allowed in 'omp atomic'.");
   }
@@ -6587,6 +6588,10 @@
   CGM.getOpenMPRuntime().emitMasterRegion(*this, CodeGen, S.getBeginLoc());
 }
 
+void CodeGenFunction::EmitOMPMetaDirective(const OMPMetaDirective &S) {
+  EmitStmt(S.getIfStmt());
+}
+
 void CodeGenFunction::EmitOMPParallelMasterTaskLoopDirective(
     const OMPParallelMasterTaskLoopDirective &S) {
   auto &&CodeGen = [this, &S](CodeGenFunction &CGF, PrePostActionTy &Action) {
Index: clang/lib/CodeGen/CGStmt.cpp
===================================================================
--- clang/lib/CodeGen/CGStmt.cpp
+++ clang/lib/CodeGen/CGStmt.cpp
@@ -194,6 +194,9 @@
   case Stmt::SEHTryStmtClass:
     EmitSEHTryStmt(cast<SEHTryStmt>(*S));
     break;
+  case Stmt::OMPMetaDirectiveClass:
+    EmitOMPMetaDirective(cast<OMPMetaDirective>(*S));
+    break;
   case Stmt::OMPParallelDirectiveClass:
     EmitOMPParallelDirective(cast<OMPParallelDirective>(*S));
     break;
Index: clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -709,6 +709,7 @@
     case OMPD_parallel_master_taskloop:
     case OMPD_parallel_master_taskloop_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
     case OMPD_unknown:
     default:
       llvm_unreachable("Unexpected directive.");
@@ -790,6 +791,7 @@
   case OMPD_parallel_master_taskloop:
   case OMPD_parallel_master_taskloop_simd:
   case OMPD_requires:
+  case OMPD_metadirective:
   case OMPD_unknown:
   default:
     break;
@@ -964,6 +966,7 @@
     case OMPD_parallel_master_taskloop:
     case OMPD_parallel_master_taskloop_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
     case OMPD_unknown:
     default:
       llvm_unreachable("Unexpected directive.");
@@ -1051,6 +1054,7 @@
   case OMPD_parallel_master_taskloop:
   case OMPD_parallel_master_taskloop_simd:
   case OMPD_requires:
+  case OMPD_metadirective:
   case OMPD_unknown:
   default:
     break;
Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp
===================================================================
--- clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -6982,6 +6982,7 @@
   case OMPD_parallel_master_taskloop_simd:
   case OMPD_requires:
   case OMPD_unknown:
+  case OMPD_metadirective:
     break;
   default:
     break;
@@ -9030,6 +9031,7 @@
     case OMPD_parallel_master_taskloop:
     case OMPD_parallel_master_taskloop_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
     case OMPD_unknown:
     default:
       llvm_unreachable("Unexpected directive.");
@@ -10499,6 +10501,7 @@
     case OMPD_target_parallel_for:
     case OMPD_target_parallel_for_simd:
     case OMPD_requires:
+    case OMPD_metadirective:
     case OMPD_unknown:
     default:
       llvm_unreachable("Unexpected standalone target data directive.");
Index: clang/lib/Basic/OpenMPKinds.cpp
===================================================================
--- clang/lib/Basic/OpenMPKinds.cpp
+++ clang/lib/Basic/OpenMPKinds.cpp
@@ -180,6 +180,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
     break;
   default:
     break;
@@ -420,6 +421,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
     break;
   default:
     break;
@@ -578,6 +580,9 @@
     OpenMPDirectiveKind DKind) {
   assert(unsigned(DKind) < llvm::omp::Directive_enumSize);
   switch (DKind) {
+  case OMPD_metadirective:
+    CaptureRegions.push_back(OMPD_metadirective);
+    break;
   case OMPD_parallel:
   case OMPD_parallel_for:
   case OMPD_parallel_for_simd:
Index: clang/lib/AST/StmtProfile.cpp
===================================================================
--- clang/lib/AST/StmtProfile.cpp
+++ clang/lib/AST/StmtProfile.cpp
@@ -847,6 +847,10 @@
       P.Visit(*I);
 }
 
+void StmtProfiler::VisitOMPMetaDirective(const OMPMetaDirective *S) {
+  VisitOMPExecutableDirective(S);
+}
+
 void StmtProfiler::VisitOMPLoopDirective(const OMPLoopDirective *S) {
   VisitOMPExecutableDirective(S);
 }
Index: clang/lib/AST/StmtPrinter.cpp
===================================================================
--- clang/lib/AST/StmtPrinter.cpp
+++ clang/lib/AST/StmtPrinter.cpp
@@ -650,6 +650,11 @@
     PrintStmt(S->getRawStmt());
 }
 
+void StmtPrinter::VisitOMPMetaDirective(OMPMetaDirective *Node) {
+  Indent() << "#pragma omp metadirective";
+  PrintOMPExecutableDirective(Node);
+}
+
 void StmtPrinter::VisitOMPParallelDirective(OMPParallelDirective *Node) {
   Indent() << "#pragma omp parallel";
   PrintOMPExecutableDirective(Node);
Index: clang/lib/AST/StmtOpenMP.cpp
===================================================================
--- clang/lib/AST/StmtOpenMP.cpp
+++ clang/lib/AST/StmtOpenMP.cpp
@@ -191,6 +191,25 @@
   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);
+  Dir->setIfStmt(IfStmt);
+  return Dir;
+}
+
+OMPMetaDirective *OMPMetaDirective::CreateEmpty(const ASTContext &C,
+                                                unsigned NumClauses,
+                                                EmptyShell) {
+  return createEmptyDirective<OMPMetaDirective>(C, NumClauses,
+                                                /*HasAssociatedStmt=*/true,
+                                                /*NumChildren=*/1);
+}
+
 OMPParallelDirective *OMPParallelDirective::Create(
     const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
     ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt, Expr *TaskRedRef,
Index: clang/lib/AST/OpenMPClause.cpp
===================================================================
--- clang/lib/AST/OpenMPClause.cpp
+++ clang/lib/AST/OpenMPClause.cpp
@@ -156,6 +156,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
     break;
   default:
     break;
@@ -250,6 +251,7 @@
   case OMPC_exclusive:
   case OMPC_uses_allocators:
   case OMPC_affinity:
+  case OMPC_when:
     break;
   default:
     break;
Index: clang/include/clang/Serialization/ASTBitCodes.h
===================================================================
--- clang/include/clang/Serialization/ASTBitCodes.h
+++ clang/include/clang/Serialization/ASTBitCodes.h
@@ -1830,21 +1830,21 @@
       /// A CXXBoolLiteralExpr record.
       EXPR_CXX_BOOL_LITERAL,
 
-      EXPR_CXX_NULL_PTR_LITERAL,  // CXXNullPtrLiteralExpr
-      EXPR_CXX_TYPEID_EXPR,       // CXXTypeidExpr (of expr).
-      EXPR_CXX_TYPEID_TYPE,       // CXXTypeidExpr (of type).
-      EXPR_CXX_THIS,              // CXXThisExpr
-      EXPR_CXX_THROW,             // CXXThrowExpr
-      EXPR_CXX_DEFAULT_ARG,       // CXXDefaultArgExpr
-      EXPR_CXX_DEFAULT_INIT,      // CXXDefaultInitExpr
-      EXPR_CXX_BIND_TEMPORARY,    // CXXBindTemporaryExpr
+      EXPR_CXX_NULL_PTR_LITERAL, // CXXNullPtrLiteralExpr
+      EXPR_CXX_TYPEID_EXPR,      // CXXTypeidExpr (of expr).
+      EXPR_CXX_TYPEID_TYPE,      // CXXTypeidExpr (of type).
+      EXPR_CXX_THIS,             // CXXThisExpr
+      EXPR_CXX_THROW,            // CXXThrowExpr
+      EXPR_CXX_DEFAULT_ARG,      // CXXDefaultArgExpr
+      EXPR_CXX_DEFAULT_INIT,     // CXXDefaultInitExpr
+      EXPR_CXX_BIND_TEMPORARY,   // CXXBindTemporaryExpr
 
       EXPR_CXX_SCALAR_VALUE_INIT, // CXXScalarValueInitExpr
       EXPR_CXX_NEW,               // CXXNewExpr
       EXPR_CXX_DELETE,            // CXXDeleteExpr
       EXPR_CXX_PSEUDO_DESTRUCTOR, // CXXPseudoDestructorExpr
 
-      EXPR_EXPR_WITH_CLEANUPS,    // ExprWithCleanups
+      EXPR_EXPR_WITH_CLEANUPS, // ExprWithCleanups
 
       EXPR_CXX_DEPENDENT_SCOPE_MEMBER,   // CXXDependentScopeMemberExpr
       EXPR_CXX_DEPENDENT_SCOPE_DECL_REF, // DependentScopeDeclRefExpr
@@ -1852,41 +1852,42 @@
       EXPR_CXX_UNRESOLVED_MEMBER,        // UnresolvedMemberExpr
       EXPR_CXX_UNRESOLVED_LOOKUP,        // UnresolvedLookupExpr
 
-      EXPR_CXX_EXPRESSION_TRAIT,  // ExpressionTraitExpr
-      EXPR_CXX_NOEXCEPT,          // CXXNoexceptExpr
+      EXPR_CXX_EXPRESSION_TRAIT, // ExpressionTraitExpr
+      EXPR_CXX_NOEXCEPT,         // CXXNoexceptExpr
 
-      EXPR_OPAQUE_VALUE,          // OpaqueValueExpr
-      EXPR_BINARY_CONDITIONAL_OPERATOR,  // BinaryConditionalOperator
-      EXPR_TYPE_TRAIT,            // TypeTraitExpr
-      EXPR_ARRAY_TYPE_TRAIT,      // ArrayTypeTraitIntExpr
+      EXPR_OPAQUE_VALUE,                // OpaqueValueExpr
+      EXPR_BINARY_CONDITIONAL_OPERATOR, // BinaryConditionalOperator
+      EXPR_TYPE_TRAIT,                  // TypeTraitExpr
+      EXPR_ARRAY_TYPE_TRAIT,            // ArrayTypeTraitIntExpr
 
-      EXPR_PACK_EXPANSION,        // PackExpansionExpr
-      EXPR_SIZEOF_PACK,           // SizeOfPackExpr
-      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM, // SubstNonTypeTemplateParmExpr
-      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK,// SubstNonTypeTemplateParmPackExpr
-      EXPR_FUNCTION_PARM_PACK,    // FunctionParmPackExpr
-      EXPR_MATERIALIZE_TEMPORARY, // MaterializeTemporaryExpr
-      EXPR_CXX_FOLD,              // CXXFoldExpr
-      EXPR_CONCEPT_SPECIALIZATION,// ConceptSpecializationExpr
-      EXPR_REQUIRES,              // RequiresExpr
+      EXPR_PACK_EXPANSION,                    // PackExpansionExpr
+      EXPR_SIZEOF_PACK,                       // SizeOfPackExpr
+      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM,      // SubstNonTypeTemplateParmExpr
+      EXPR_SUBST_NON_TYPE_TEMPLATE_PARM_PACK, // SubstNonTypeTemplateParmPackExpr
+      EXPR_FUNCTION_PARM_PACK,                // FunctionParmPackExpr
+      EXPR_MATERIALIZE_TEMPORARY,             // MaterializeTemporaryExpr
+      EXPR_CXX_FOLD,                          // CXXFoldExpr
+      EXPR_CONCEPT_SPECIALIZATION,            // ConceptSpecializationExpr
+      EXPR_REQUIRES,                          // RequiresExpr
 
       // CUDA
-      EXPR_CUDA_KERNEL_CALL,       // CUDAKernelCallExpr
+      EXPR_CUDA_KERNEL_CALL, // CUDAKernelCallExpr
 
       // OpenCL
-      EXPR_ASTYPE,                 // AsTypeExpr
+      EXPR_ASTYPE, // AsTypeExpr
 
       // Microsoft
-      EXPR_CXX_PROPERTY_REF_EXPR, // MSPropertyRefExpr
+      EXPR_CXX_PROPERTY_REF_EXPR,       // MSPropertyRefExpr
       EXPR_CXX_PROPERTY_SUBSCRIPT_EXPR, // MSPropertySubscriptExpr
-      EXPR_CXX_UUIDOF_EXPR,       // CXXUuidofExpr (of expr).
-      EXPR_CXX_UUIDOF_TYPE,       // CXXUuidofExpr (of type).
-      STMT_SEH_LEAVE,             // SEHLeaveStmt
-      STMT_SEH_EXCEPT,            // SEHExceptStmt
-      STMT_SEH_FINALLY,           // SEHFinallyStmt
-      STMT_SEH_TRY,               // SEHTryStmt
+      EXPR_CXX_UUIDOF_EXPR,             // CXXUuidofExpr (of expr).
+      EXPR_CXX_UUIDOF_TYPE,             // CXXUuidofExpr (of type).
+      STMT_SEH_LEAVE,                   // SEHLeaveStmt
+      STMT_SEH_EXCEPT,                  // SEHExceptStmt
+      STMT_SEH_FINALLY,                 // SEHFinallyStmt
+      STMT_SEH_TRY,                     // SEHTryStmt
 
       // OpenMP directives
+      STMT_OMP_META_DIRECTIVE,
       STMT_OMP_PARALLEL_DIRECTIVE,
       STMT_OMP_SIMD_DIRECTIVE,
       STMT_OMP_FOR_DIRECTIVE,
@@ -1946,10 +1947,10 @@
       EXPR_OMP_ITERATOR,
 
       // ARC
-      EXPR_OBJC_BRIDGED_CAST,     // ObjCBridgedCastExpr
+      EXPR_OBJC_BRIDGED_CAST, // ObjCBridgedCastExpr
 
-      STMT_MS_DEPENDENT_EXISTS,   // MSDependentExistsStmt
-      EXPR_LAMBDA,                // LambdaExpr
+      STMT_MS_DEPENDENT_EXISTS, // MSDependentExistsStmt
+      EXPR_LAMBDA,              // LambdaExpr
       STMT_COROUTINE_BODY,
       STMT_CORETURN,
       EXPR_COAWAIT,
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -10298,6 +10298,11 @@
   void ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init);
 
   // OpenMP directives and clauses.
+  /// Called on well-formed '\#pragma omp metadirective' after parsing
+  /// of the  associated statement.
+  StmtResult ActOnOpenMPMetaDirective(ArrayRef<OMPClause *> Clauses,
+                                      Stmt *AStmt, SourceLocation StartLoc,
+                                      SourceLocation EndLoc);
   /// Called on correct id-expression from the '#pragma omp
   /// threadprivate'.
   ExprResult ActOnOpenMPIdExpression(Scope *CurScope, CXXScopeSpec &ScopeSpec,
@@ -10793,6 +10798,10 @@
                                      SourceLocation StartLoc,
                                      SourceLocation LParenLoc,
                                      SourceLocation EndLoc);
+  /// Called on well-formed 'when' clause.
+  OMPClause *ActOnOpenMPWhenClause(OMPTraitInfo &TI, SourceLocation StartLoc,
+                                   SourceLocation LParenLoc,
+                                   SourceLocation EndLoc);
   /// Called on well-formed 'default' clause.
   OMPClause *ActOnOpenMPDefaultClause(llvm::omp::DefaultKind Kind,
                                       SourceLocation KindLoc,
Index: clang/include/clang/Basic/StmtNodes.td
===================================================================
--- clang/include/clang/Basic/StmtNodes.td
+++ clang/include/clang/Basic/StmtNodes.td
@@ -217,6 +217,7 @@
 
 // OpenMP Directives.
 def OMPExecutableDirective : StmtNode<Stmt, 1>;
+def OMPMetaDirective : StmtNode<OMPExecutableDirective>;
 def OMPLoopDirective : StmtNode<OMPExecutableDirective, 1>;
 def OMPParallelDirective : StmtNode<OMPExecutableDirective>;
 def OMPSimdDirective : StmtNode<OMPLoopDirective>;
Index: clang/include/clang/Basic/DiagnosticParseKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticParseKinds.td
+++ clang/include/clang/Basic/DiagnosticParseKinds.td
@@ -1377,6 +1377,10 @@
   "only a single match extension allowed per OpenMP context selector">;
 def err_omp_invalid_dsa: Error<
   "data-sharing attribute '%0' in '%1' clause requires OpenMP version %2 or above">;
+def err_omp_expected_colon: Error<
+  "missing ':' in %0">;
+def err_omp_expected_context_selector: Error<
+  "expected valid context selector in %0">;
 
 // Pragma loop support.
 def err_pragma_loop_missing_argument : Error<
Index: clang/include/clang/AST/StmtOpenMP.h
===================================================================
--- clang/include/clang/AST/StmtOpenMP.h
+++ clang/include/clang/AST/StmtOpenMP.h
@@ -362,6 +362,44 @@
   }
 };
 
+/// This represents '#pragma omp metadirective' directive.
+///
+/// \code
+/// #pragma omp metadirective when(user={condition(N>10)}: parallel for)
+/// \endcode
+/// In this example directive '#pragma omp metadirective' has clauses 'when'
+/// with a dynamic user condition to check if a variable 'N > 10'
+///
+class OMPMetaDirective final : public OMPExecutableDirective {
+  friend class ASTStmtReader;
+  friend class OMPExecutableDirective;
+  Stmt *IfStmt;
+
+  OMPMetaDirective(SourceLocation StartLoc, SourceLocation EndLoc)
+      : OMPExecutableDirective(OMPMetaDirectiveClass,
+                               llvm::omp::OMPD_metadirective, StartLoc,
+                               EndLoc) {}
+  explicit OMPMetaDirective()
+      : OMPExecutableDirective(OMPMetaDirectiveClass,
+                               llvm::omp::OMPD_metadirective, SourceLocation(),
+                               SourceLocation()) {}
+
+public:
+  static OMPMetaDirective *Create(const ASTContext &C, SourceLocation StartLoc,
+                                  SourceLocation EndLoc,
+                                  ArrayRef<OMPClause *> Clauses,
+                                  Stmt *AssociatedStmt, Stmt *IfStmt);
+  static OMPMetaDirective *CreateEmpty(const ASTContext &C, unsigned NumClauses,
+                                       EmptyShell);
+
+  void setIfStmt(Stmt *stmt) { IfStmt = stmt; }
+  Stmt *getIfStmt() const { return IfStmt; }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == OMPMetaDirectiveClass;
+  }
+};
+
 /// This represents '#pragma omp parallel' directive.
 ///
 /// \code
Index: clang/include/clang/AST/RecursiveASTVisitor.h
===================================================================
--- clang/include/clang/AST/RecursiveASTVisitor.h
+++ clang/include/clang/AST/RecursiveASTVisitor.h
@@ -2780,6 +2780,9 @@
   return TraverseOMPExecutableDirective(S);
 }
 
+DEF_TRAVERSE_STMT(OMPMetaDirective,
+                  { TRY_TO(TraverseOMPExecutableDirective(S)); })
+
 DEF_TRAVERSE_STMT(OMPParallelDirective,
                   { TRY_TO(TraverseOMPExecutableDirective(S)); })
 
Index: clang/include/clang-c/Index.h
===================================================================
--- clang/include/clang-c/Index.h
+++ clang/include/clang-c/Index.h
@@ -2568,7 +2568,11 @@
    */
   CXCursor_OMPScanDirective = 287,
 
-  CXCursor_LastStmt = CXCursor_OMPScanDirective,
+  /** OpenMP metadirective directive.
+   */
+  CXCursor_OMPMetaDirective = 288,
+
+  CXCursor_LastStmt = CXCursor_OMPMetaDirective,
 
   /**
    * Cursor that represents the translation unit itself.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to