alokmishra.besu updated this revision to Diff 314229. alokmishra.besu added a comment.
Rebased with current branch to avoid patch failure 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/DiagnosticSemaKinds.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_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
Index: llvm/include/llvm/Frontend/OpenMP/OMP.td =================================================================== --- llvm/include/llvm/Frontend/OpenMP/OMP.td +++ llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -60,6 +60,7 @@ let clangClass = "OMPCollapseClause"; let flangClassValue = "ScalarIntConstantExpr"; } +def OMPC_When: Clause<"when"> {} def OMPC_Default : Clause<"default"> { let clangClass = "OMPDefaultClause"; let flangClassValue = "OmpDefaultClause"; @@ -319,6 +320,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 @@ -5526,6 +5526,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}} expected-error {{use of undeclared identifier 'xyz'}} + ; +#pragma omp metadirective when(device = {arch(nvptx)} : parallel default() // expected-error {{expected ',' or ')' in 'when' clause}} expected-error {{expected expression}} + ; +} 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: 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: 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: 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: 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: 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.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 @@ -8381,6 +8381,15 @@ template <typename Derived> StmtResult +TreeTransform<Derived>::TransformOMPMetaDirective(OMPMetaDirective *D) { + // TODO: Fix This + SemaRef.Diag(D->getBeginLoc(), diag::err_omp_instantiation_not_supported) + << getOpenMPDirectiveName(D->getDirectiveKind()); + return StmtError(); +} + +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 @@ -3843,6 +3843,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: @@ -5554,6 +5555,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: @@ -5672,6 +5674,7 @@ case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_when: default: llvm_unreachable("Unexpected clause"); } @@ -11999,6 +12002,7 @@ case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -12152,6 +12156,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: @@ -12231,6 +12236,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: @@ -12308,6 +12314,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: @@ -12385,6 +12392,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: @@ -12462,6 +12470,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: @@ -12539,6 +12548,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: @@ -12616,6 +12626,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: @@ -12695,12 +12706,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: @@ -13208,6 +13229,7 @@ case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -13447,6 +13469,7 @@ case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -13685,6 +13708,7 @@ case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: default: llvm_unreachable("Clause is not allowed."); } @@ -13963,6 +13987,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 @@ -2206,6 +2206,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; @@ -2261,6 +2262,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(ParsedStmtContext StmtCtx) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); + static bool ReadDirectiveWithinMetadirective = false; ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); SmallVector<OMPClause *, 5> Clauses; @@ -2269,8 +2271,14 @@ FirstClauses(llvm::omp::Clause_enumSize + 1); unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; - SourceLocation Loc = ConsumeAnnotationToken(), EndLoc; + if (!ReadDirectiveWithinMetadirective) + ConsumeAnnotationToken(); + SourceLocation Loc = Tok.getLocation(), EndLoc; OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); + if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) { + Diag(Tok, diag::err_omp_unknown_directive); + return StmtError(); + } OpenMPDirectiveKind CancelRegion = OMPD_unknown; // Name of critical directive. DeclarationNameInfo DirName; @@ -2278,6 +2286,136 @@ bool HasAssociatedStatement = true; switch (DKind) { + case OMPD_metadirective: { + ConsumeToken(); + SmallVector<VariantMatchInfo, 4> VMIs; + + // 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 + int BestIdx = getBestVariantMatchForContext(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 + ReadDirectiveWithinMetadirective = true; + Directive = ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); + ReadDirectiveWithinMetadirective = false; + break; + } + break; + } case OMPD_threadprivate: { // FIXME: Should this be permitted in C++? if ((StmtCtx & ParsedStmtContext::AllowDeclarationsInC) == @@ -2464,6 +2602,13 @@ Actions.StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), Loc); while (Tok.isNot(tok::annot_pragma_openmp_end)) { + // 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)) + ConsumeToken(); + break; + } bool HasImplicitClause = false; if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { HasImplicitClause = true; @@ -2880,6 +3025,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 @@ -3387,6 +3387,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 @@ -710,6 +710,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: llvm_unreachable("Unexpected directive."); } @@ -791,6 +792,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: break; } @@ -965,6 +967,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: llvm_unreachable("Unexpected directive."); } @@ -1052,6 +1055,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: break; } Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -6983,6 +6983,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: break; default: break; @@ -9500,6 +9501,7 @@ case OMPD_parallel_master_taskloop_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: llvm_unreachable("Unexpected directive."); } @@ -11011,6 +11013,7 @@ case OMPD_target_parallel_for_simd: case OMPD_requires: case OMPD_unknown: + case OMPD_metadirective: default: llvm_unreachable("Unexpected standalone target data directive."); break; 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 @@ -848,6 +848,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 @@ -153,6 +153,7 @@ case OMPC_exclusive: case OMPC_uses_allocators: case OMPC_affinity: + case OMPC_when: break; default: break; @@ -247,6 +248,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 @@ -1887,6 +1887,7 @@ STMT_SEH_TRY, // SEHTryStmt // OpenMP directives + STMT_OMP_META_DIRECTIVE, STMT_OMP_PARALLEL_DIRECTIVE, STMT_OMP_SIMD_DIRECTIVE, STMT_OMP_FOR_DIRECTIVE, Index: clang/include/clang/Sema/Sema.h =================================================================== --- clang/include/clang/Sema/Sema.h +++ clang/include/clang/Sema/Sema.h @@ -10250,6 +10250,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, @@ -10761,6 +10766,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/DiagnosticSemaKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticSemaKinds.td +++ clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -10524,6 +10524,8 @@ : Note<"jump bypasses OpenMP structured block">; def note_omp_exits_structured_block : Note<"jump exits scope of OpenMP structured block">; +def err_omp_instantiation_not_supported : Error< + "instantiation of '%0' not supported yet">; } // end of OpenMP category let CategoryName = "Related Result Type Issue" in { Index: clang/include/clang/Basic/DiagnosticParseKinds.td =================================================================== --- clang/include/clang/Basic/DiagnosticParseKinds.td +++ clang/include/clang/Basic/DiagnosticParseKinds.td @@ -1387,6 +1387,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 @@ -2781,6 +2781,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