Author: Krzysztof Parzyszek Date: 2024-03-06T10:46:26-06:00 New Revision: 67c82d6ffb4bbc21212116a11f390761d859297a
URL: https://github.com/llvm/llvm-project/commit/67c82d6ffb4bbc21212116a11f390761d859297a DIFF: https://github.com/llvm/llvm-project/commit/67c82d6ffb4bbc21212116a11f390761d859297a.diff LOG: [Frontend] Add leaf constructs and association to OpenMP/ACC directives (#83625) Add members "leafConstructs" and "association" to .td describing OpenMP/ACC directives. The naming follows the terminology used in the OpenMP standard: a "leaf" construct is a construct that is itself not a composition or a combination of other constructs, and "association" is the source language construct to which the directive applies (e.g. loop, block, etc.) The tblgen-generated output then contains two additional functions - getLeafConstructs(D), and - getDirectiveAssociation(D) plus "enum class Association", all in namespaces "llvm::omp" and "llvm::acc". Note: getLeafConstructs returns an empty sequence for a construct that is itself a leaf construct. Use the new functions to simplify a few OpenMP-related functions in clang. Added: Modified: clang/lib/Basic/OpenMPKinds.cpp llvm/include/llvm/Frontend/Directive/DirectiveBase.td llvm/include/llvm/Frontend/OpenACC/ACC.td llvm/include/llvm/Frontend/OpenMP/OMP.td llvm/include/llvm/TableGen/DirectiveEmitter.h llvm/test/TableGen/directive1.td llvm/test/TableGen/directive2.td llvm/utils/TableGen/DirectiveEmitter.cpp Removed: ################################################################################ diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 6c31b0824eb8a4..b3e9affbb3e58a 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -574,31 +574,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, } bool clang::isOpenMPLoopDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_simd || DKind == OMPD_for || DKind == OMPD_for_simd || - DKind == OMPD_parallel_for || DKind == OMPD_parallel_for_simd || - DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || - DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || - DKind == OMPD_parallel_master_taskloop || - DKind == OMPD_parallel_master_taskloop_simd || - DKind == OMPD_masked_taskloop || DKind == OMPD_masked_taskloop_simd || - DKind == OMPD_parallel_masked_taskloop || DKind == OMPD_distribute || - DKind == OMPD_parallel_masked_taskloop_simd || - DKind == OMPD_target_parallel_for || - DKind == OMPD_distribute_parallel_for || - DKind == OMPD_distribute_parallel_for_simd || - DKind == OMPD_distribute_simd || - DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd || - DKind == OMPD_teams_distribute || - DKind == OMPD_teams_distribute_simd || - DKind == OMPD_teams_distribute_parallel_for_simd || - DKind == OMPD_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute || - DKind == OMPD_target_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd || DKind == OMPD_tile || - DKind == OMPD_unroll || DKind == OMPD_loop || - DKind == OMPD_teams_loop || DKind == OMPD_target_teams_loop || - DKind == OMPD_parallel_loop || DKind == OMPD_target_parallel_loop; + return getDirectiveAssociation(DKind) == Association::Loop; } bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { @@ -619,44 +595,20 @@ bool clang::isOpenMPWorksharingDirective(OpenMPDirectiveKind DKind) { } bool clang::isOpenMPTaskLoopDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_taskloop || DKind == OMPD_taskloop_simd || - DKind == OMPD_master_taskloop || DKind == OMPD_master_taskloop_simd || - DKind == OMPD_parallel_master_taskloop || - DKind == OMPD_masked_taskloop || DKind == OMPD_masked_taskloop_simd || - DKind == OMPD_parallel_masked_taskloop || - DKind == OMPD_parallel_masked_taskloop_simd || - DKind == OMPD_parallel_master_taskloop_simd; + return DKind == OMPD_taskloop || + llvm::is_contained(getLeafConstructs(DKind), OMPD_taskloop); } bool clang::isOpenMPParallelDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_parallel || DKind == OMPD_parallel_for || - DKind == OMPD_parallel_for_simd || DKind == OMPD_parallel_sections || - DKind == OMPD_target_parallel || DKind == OMPD_target_parallel_for || - DKind == OMPD_distribute_parallel_for || - DKind == OMPD_distribute_parallel_for_simd || - DKind == OMPD_target_parallel_for_simd || - DKind == OMPD_teams_distribute_parallel_for || - DKind == OMPD_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_parallel_master || DKind == OMPD_parallel_masked || - DKind == OMPD_parallel_master_taskloop || - DKind == OMPD_parallel_master_taskloop_simd || - DKind == OMPD_parallel_masked_taskloop || - DKind == OMPD_parallel_masked_taskloop_simd || - DKind == OMPD_parallel_loop || DKind == OMPD_target_parallel_loop || - DKind == OMPD_teams_loop; + if (DKind == OMPD_teams_loop) + return true; + return DKind == OMPD_parallel || + llvm::is_contained(getLeafConstructs(DKind), OMPD_parallel); } bool clang::isOpenMPTargetExecutionDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_target || DKind == OMPD_target_parallel || - DKind == OMPD_target_parallel_for || - DKind == OMPD_target_parallel_for_simd || DKind == OMPD_target_simd || - DKind == OMPD_target_teams || DKind == OMPD_target_teams_distribute || - DKind == OMPD_target_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd || - DKind == OMPD_target_teams_loop || DKind == OMPD_target_parallel_loop; + return DKind == OMPD_target || + llvm::is_contained(getLeafConstructs(DKind), OMPD_target); } bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) { @@ -665,60 +617,45 @@ bool clang::isOpenMPTargetDataManagementDirective(OpenMPDirectiveKind DKind) { } bool clang::isOpenMPNestingTeamsDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_teams || DKind == OMPD_teams_distribute || - DKind == OMPD_teams_distribute_simd || - DKind == OMPD_teams_distribute_parallel_for_simd || - DKind == OMPD_teams_distribute_parallel_for || - DKind == OMPD_teams_loop; + if (DKind == OMPD_teams) + return true; + ArrayRef<Directive> Leaves = getLeafConstructs(DKind); + return !Leaves.empty() && Leaves.front() == OMPD_teams; } bool clang::isOpenMPTeamsDirective(OpenMPDirectiveKind DKind) { - return isOpenMPNestingTeamsDirective(DKind) || DKind == OMPD_target_teams || - DKind == OMPD_target_teams_distribute || - DKind == OMPD_target_teams_distribute_parallel_for || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd || - DKind == OMPD_target_teams_loop; + return DKind == OMPD_teams || + llvm::is_contained(getLeafConstructs(DKind), OMPD_teams); } bool clang::isOpenMPSimdDirective(OpenMPDirectiveKind DKind) { - return DKind == OMPD_simd || DKind == OMPD_for_simd || - DKind == OMPD_parallel_for_simd || DKind == OMPD_taskloop_simd || - DKind == OMPD_master_taskloop_simd || - DKind == OMPD_masked_taskloop_simd || - DKind == OMPD_parallel_master_taskloop_simd || - DKind == OMPD_parallel_masked_taskloop_simd || - DKind == OMPD_distribute_parallel_for_simd || - DKind == OMPD_distribute_simd || DKind == OMPD_target_simd || - DKind == OMPD_teams_distribute_simd || - DKind == OMPD_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_parallel_for_simd || - DKind == OMPD_target_teams_distribute_simd || - DKind == OMPD_target_parallel_for_simd; + // Avoid OMPD_declare_simd + if (getDirectiveAssociation(DKind) != Association::Loop) + return false; + // Formally, OMPD_end_do_simd also has a loop association, but + // it's a Fortran-specific directive. + + return DKind == OMPD_simd || + llvm::is_contained(getLeafConstructs(DKind), OMPD_simd); } bool clang::isOpenMPNestingDistributeDirective(OpenMPDirectiveKind Kind) { - return Kind == OMPD_distribute || Kind == OMPD_distribute_parallel_for || - Kind == OMPD_distribute_parallel_for_simd || - Kind == OMPD_distribute_simd; - // TODO add next directives. + if (Kind == OMPD_distribute) + return true; + ArrayRef<Directive> Leaves = getLeafConstructs(Kind); + return !Leaves.empty() && Leaves.front() == OMPD_distribute; } bool clang::isOpenMPDistributeDirective(OpenMPDirectiveKind Kind) { - return isOpenMPNestingDistributeDirective(Kind) || - Kind == OMPD_teams_distribute || Kind == OMPD_teams_distribute_simd || - Kind == OMPD_teams_distribute_parallel_for_simd || - Kind == OMPD_teams_distribute_parallel_for || - Kind == OMPD_target_teams_distribute || - Kind == OMPD_target_teams_distribute_parallel_for || - Kind == OMPD_target_teams_distribute_parallel_for_simd || - Kind == OMPD_target_teams_distribute_simd; + return Kind == OMPD_distribute || + llvm::is_contained(getLeafConstructs(Kind), OMPD_distribute); } bool clang::isOpenMPGenericLoopDirective(OpenMPDirectiveKind Kind) { - return Kind == OMPD_loop || Kind == OMPD_teams_loop || - Kind == OMPD_target_teams_loop || Kind == OMPD_parallel_loop || - Kind == OMPD_target_parallel_loop; + if (Kind == OMPD_loop) + return true; + ArrayRef<Directive> Leaves = getLeafConstructs(Kind); + return !Leaves.empty() && Leaves.back() == OMPD_loop; } bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { diff --git a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td index 31578710365b21..ce532e0cfae297 100644 --- a/llvm/include/llvm/Frontend/Directive/DirectiveBase.td +++ b/llvm/include/llvm/Frontend/Directive/DirectiveBase.td @@ -127,6 +127,35 @@ class VersionedClause<Clause c, int min = 1, int max = 0x7FFFFFFF> { int maxVersion = max; } +// Kinds of directive associations. +class Association<string n> { + string name = n; // Name of the enum value in enum class Association. +} +// All of the AS_Xyz names are recognized by TableGen in order to calculate +// the association in the AS_FromLeaves case. +def AS_None : Association<"None"> {} // No association +def AS_Block : Association<"Block"> {} // Block (incl. single + // statement) +def AS_Declaration : Association<"Declaration"> {} // Declaration +def AS_Delimited : Association<"Delimited"> {} // Region delimited with + // begin/end +def AS_Loop : Association<"Loop"> {} // Loop +def AS_Separating : Association<"Separating"> {} // Separates parts of a + // construct + +def AS_FromLeaves : Association<"FromLeaves"> {} // See below +// AS_FromLeaves can be used for combined/composite directives, and the actual +// association will be computed based on associations of the leaf constructs: +// (x + y) + z = x + (y + z) +// x + y = y + x +// x + x = x +// AS_None + x = x +// AS_Block + AS_Loop = AS_Loop +// Other combinations are not allowed. +// This association is not valid for leaf constructs. +// The name "AS_FromLeaves" is recognized by TableGen, and there is no enum +// generated for it. + // Information about a specific directive. class Directive<string d> { // Name of the directive. Can be composite directive sepearted by whitespace. @@ -152,6 +181,13 @@ class Directive<string d> { // List of clauses that are required. list<VersionedClause> requiredClauses = []; + // List of leaf constituent directives in the order in which they appear + // in the combined/composite directive. + list<Directive> leafConstructs = []; + // Set directive used by default when unknown. bit isDefault = false; + + // What the directive is associated with. + Association association = AS_FromLeaves; } diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td index 0dbd934d83f064..dfa6a222e9f77c 100644 --- a/llvm/include/llvm/Frontend/OpenACC/ACC.td +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -266,7 +266,9 @@ def ACCC_Unknown : Clause<"unknown"> { //===----------------------------------------------------------------------===// // 2.12 -def ACC_Atomic : Directive<"atomic"> {} +def ACC_Atomic : Directive<"atomic"> { + let association = AS_Block; +} // 2.6.5 def ACC_Data : Directive<"data"> { @@ -290,6 +292,7 @@ def ACC_Data : Directive<"data"> { VersionedClause<ACCC_NoCreate>, VersionedClause<ACCC_Present> ]; + let association = AS_Block; } // 2.13 @@ -304,6 +307,7 @@ def ACC_Declare : Directive<"declare"> { VersionedClause<ACCC_DeviceResident>, VersionedClause<ACCC_Link> ]; + let association = AS_None; } // 2.5.3 @@ -329,6 +333,7 @@ def ACC_Kernels : Directive<"kernels"> { VersionedClause<ACCC_Self>, VersionedClause<ACCC_VectorLength> ]; + let association = AS_Block; } // 2.5.1 @@ -357,6 +362,7 @@ def ACC_Parallel : Directive<"parallel"> { VersionedClause<ACCC_If>, VersionedClause<ACCC_Self> ]; + let association = AS_Block; } // 2.5.2 @@ -384,6 +390,7 @@ def ACC_Serial : Directive<"serial"> { VersionedClause<ACCC_If>, VersionedClause<ACCC_Self> ]; + let association = AS_Block; } // 2.9 @@ -403,10 +410,13 @@ def ACC_Loop : Directive<"loop"> { VersionedClause<ACCC_Independent>, VersionedClause<ACCC_Seq> ]; + let association = AS_Loop; } // 2.10 -def ACC_Cache : Directive<"cache"> {} +def ACC_Cache : Directive<"cache"> { + let association = AS_None; +} // 2.14.1 def ACC_Init : Directive<"init"> { @@ -415,6 +425,7 @@ def ACC_Init : Directive<"init"> { VersionedClause<ACCC_DeviceType>, VersionedClause<ACCC_If> ]; + let association = AS_None; } // 2.15.1 @@ -430,6 +441,7 @@ def ACC_Routine : Directive<"routine"> { let allowedOnceClauses = [ VersionedClause<ACCC_NoHost> ]; + let association = AS_Declaration; } // 2.14.3 @@ -448,6 +460,7 @@ def ACC_Set : Directive<"set"> { VersionedClause<ACCC_DeviceNum>, VersionedClause<ACCC_DeviceType> ]; + let association = AS_None; } // 2.14.2 @@ -457,6 +470,7 @@ def ACC_Shutdown : Directive<"shutdown"> { VersionedClause<ACCC_DeviceType>, VersionedClause<ACCC_If> ]; + let association = AS_None; } // 2.14.4 @@ -475,6 +489,7 @@ def ACC_Update : Directive<"update"> { VersionedClause<ACCC_Host>, VersionedClause<ACCC_Self> ]; + let association = AS_None; } // 2.16.3 @@ -483,6 +498,7 @@ def ACC_Wait : Directive<"wait"> { VersionedClause<ACCC_Async>, VersionedClause<ACCC_If> ]; + let association = AS_None; } // 2.14.6 @@ -499,6 +515,7 @@ def ACC_EnterData : Directive<"enter data"> { VersionedClause<ACCC_Create>, VersionedClause<ACCC_Copyin> ]; + let association = AS_None; } // 2.14.7 @@ -516,6 +533,7 @@ def ACC_ExitData : Directive<"exit data"> { VersionedClause<ACCC_Delete>, VersionedClause<ACCC_Detach> ]; + let association = AS_None; } // 2.8 @@ -527,6 +545,7 @@ def ACC_HostData : Directive<"host_data"> { let requiredClauses = [ VersionedClause<ACCC_UseDevice> ]; + let association = AS_Block; } // 2.11 @@ -564,6 +583,7 @@ def ACC_KernelsLoop : Directive<"kernels loop"> { VersionedClause<ACCC_Independent>, VersionedClause<ACCC_Seq> ]; + let leafConstructs = [ACC_Kernels, ACC_Loop]; } // 2.11 @@ -602,6 +622,7 @@ def ACC_ParallelLoop : Directive<"parallel loop"> { VersionedClause<ACCC_Independent>, VersionedClause<ACCC_Seq> ]; + let leafConstructs = [ACC_Parallel, ACC_Loop]; } // 2.11 @@ -637,8 +658,10 @@ def ACC_SerialLoop : Directive<"serial loop"> { VersionedClause<ACCC_Independent>, VersionedClause<ACCC_Seq> ]; + let leafConstructs = [ACC_Serial, ACC_Loop]; } def ACC_Unknown : Directive<"unknown"> { let isDefault = true; + let association = AS_None; } diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td index 77d207f2b10a83..d9a931438b4292 100644 --- a/llvm/include/llvm/Frontend/OpenMP/OMP.td +++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td @@ -463,7 +463,9 @@ def OMPC_OMX_Bare : Clause<"ompx_bare"> { // Definition of OpenMP directives //===----------------------------------------------------------------------===// -def OMP_ThreadPrivate : Directive<"threadprivate"> {} +def OMP_ThreadPrivate : Directive<"threadprivate"> { + let association = AS_None; +} def OMP_Parallel : Directive<"parallel"> { let allowedClauses = [ VersionedClause<OMPC_Private>, @@ -480,6 +482,7 @@ def OMP_Parallel : Directive<"parallel"> { VersionedClause<OMPC_NumThreads>, VersionedClause<OMPC_ProcBind>, ]; + let association = AS_Block; } def OMP_Task : Directive<"task"> { let allowedClauses = [ @@ -500,6 +503,7 @@ def OMP_Task : Directive<"task"> { VersionedClause<OMPC_Final>, VersionedClause<OMPC_Priority> ]; + let association = AS_Block; } def OMP_Simd : Directive<"simd"> { let allowedClauses = [ @@ -518,17 +522,20 @@ def OMP_Simd : Directive<"simd"> { VersionedClause<OMPC_If, 50>, VersionedClause<OMPC_Order, 50> ]; + let association = AS_Loop; } def OMP_Tile : Directive<"tile"> { let allowedOnceClauses = [ VersionedClause<OMPC_Sizes, 51>, ]; + let association = AS_Loop; } def OMP_Unroll : Directive<"unroll"> { let allowedOnceClauses = [ VersionedClause<OMPC_Full, 51>, VersionedClause<OMPC_Partial, 51>, ]; + let association = AS_Loop; } def OMP_For : Directive<"for"> { let allowedClauses = [ @@ -544,6 +551,7 @@ def OMP_For : Directive<"for"> { VersionedClause<OMPC_Allocate>, VersionedClause<OMPC_Order, 50> ]; + let association = AS_Loop; } def OMP_Do : Directive<"do"> { let allowedClauses = [ @@ -560,6 +568,7 @@ def OMP_Do : Directive<"do"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Order, 50> ]; + let association = AS_Loop; } def OMP_Sections : Directive<"sections"> { let allowedClauses = [ @@ -570,8 +579,11 @@ def OMP_Sections : Directive<"sections"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Allocate> ]; + let association = AS_Block; +} +def OMP_Section : Directive<"section"> { + let association = AS_Separating; } -def OMP_Section : Directive<"section"> {} def OMP_Single : Directive<"single"> { let allowedClauses = [ VersionedClause<OMPC_Private>, @@ -580,33 +592,44 @@ def OMP_Single : Directive<"single"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Allocate> ]; + let association = AS_Block; +} +def OMP_Master : Directive<"master"> { + let association = AS_Block; } -def OMP_Master : Directive<"master"> {} def OMP_Critical : Directive<"critical"> { let allowedClauses = [ VersionedClause<OMPC_Hint> ]; + let association = AS_Block; +} +def OMP_TaskYield : Directive<"taskyield"> { + let association = AS_None; +} +def OMP_Barrier : Directive<"barrier"> { + let association = AS_None; } -def OMP_TaskYield : Directive<"taskyield"> {} -def OMP_Barrier : Directive<"barrier"> {} def OMP_Error : Directive<"error"> { let allowedClauses = [ VersionedClause<OMPC_At, 51>, VersionedClause<OMPC_Severity, 51>, VersionedClause<OMPC_Message, 51> ]; + let association = AS_None; } def OMP_TaskWait : Directive<"taskwait"> { let allowedClauses = [ VersionedClause<OMPC_Depend, 50>, VersionedClause<OMPC_NoWait, 51> ]; + let association = AS_None; } def OMP_TaskGroup : Directive<"taskgroup"> { let allowedClauses = [ VersionedClause<OMPC_TaskReduction, 50>, VersionedClause<OMPC_Allocate, 50> ]; + let association = AS_Block; } def OMP_Flush : Directive<"flush"> { let allowedOnceClauses = [ @@ -617,6 +640,7 @@ def OMP_Flush : Directive<"flush"> { // OMPKinds.def. VersionedClause<OMPC_Flush> ]; + let association = AS_None; } def OMP_Ordered : Directive<"ordered"> { let allowedClauses = [ @@ -627,6 +651,8 @@ def OMP_Ordered : Directive<"ordered"> { VersionedClause<OMPC_Threads>, VersionedClause<OMPC_Simd> ]; + let association = AS_None; + // There is also a block-associated "ordered" directive. } def OMP_Atomic : Directive<"atomic"> { let allowedClauses = [ @@ -646,6 +672,7 @@ def OMP_Atomic : Directive<"atomic"> { VersionedClause<OMPC_Fail, 51>, VersionedClause<OMPC_Weak, 51> ]; + let association = AS_Block; } def OMP_Target : Directive<"target"> { let allowedClauses = [ @@ -669,6 +696,7 @@ def OMP_Target : Directive<"target"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_OMPX_DynCGroupMem>, ]; + let association = AS_Block; } def OMP_Teams : Directive<"teams"> { let allowedClauses = [ @@ -685,11 +713,13 @@ def OMP_Teams : Directive<"teams"> { VersionedClause<OMPC_NumTeams>, VersionedClause<OMPC_ThreadLimit> ]; + let association = AS_Block; } def OMP_Cancel : Directive<"cancel"> { let allowedOnceClauses = [ VersionedClause<OMPC_If> ]; + let association = AS_None; } def OMP_Requires : Directive<"requires"> { let allowedOnceClauses = [ @@ -707,8 +737,11 @@ def OMP_Requires : Directive<"requires"> { VersionedClause<OMPC_DynamicAllocators>, VersionedClause<OMPC_AtomicDefaultMemOrder> ]; + let association = AS_None; +} +def OMP_Nothing : Directive<"nothing"> { + let association = AS_None; } -def OMP_Nothing : Directive<"nothing"> {} def OMP_TargetData : Directive<"target data"> { let allowedOnceClauses = [ VersionedClause<OMPC_Device>, @@ -719,6 +752,7 @@ def OMP_TargetData : Directive<"target data"> { VersionedClause<OMPC_UseDevicePtr>, VersionedClause<OMPC_UseDeviceAddr, 50> ]; + let association = AS_Block; } def OMP_TargetEnterData : Directive<"target enter data"> { let allowedClauses = [ @@ -732,6 +766,7 @@ def OMP_TargetEnterData : Directive<"target enter data"> { let requiredClauses = [ VersionedClause<OMPC_Map> ]; + let association = AS_None; } def OMP_TargetExitData : Directive<"target exit data"> { let allowedClauses = [ @@ -745,6 +780,7 @@ def OMP_TargetExitData : Directive<"target exit data"> { let requiredClauses = [ VersionedClause<OMPC_Map> ]; + let association = AS_None; } def OMP_TargetParallel : Directive<"target parallel"> { let allowedClauses = [ @@ -771,6 +807,7 @@ def OMP_TargetParallel : Directive<"target parallel"> { VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_ThreadLimit, 51>, ]; + let leafConstructs = [OMP_Target, OMP_Parallel]; } def OMP_TargetParallelFor : Directive<"target parallel for"> { let allowedClauses = [ @@ -803,6 +840,7 @@ def OMP_TargetParallelFor : Directive<"target parallel for"> { VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_ThreadLimit, 51>, ]; + let leafConstructs = [OMP_Target, OMP_Parallel, OMP_For]; } def OMP_TargetParallelDo : Directive<"target parallel do"> { let allowedClauses = [ @@ -833,6 +871,7 @@ def OMP_TargetParallelDo : Directive<"target parallel do"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Target, OMP_Parallel, OMP_Do]; } def OMP_TargetUpdate : Directive<"target update"> { let allowedClauses = [ @@ -845,6 +884,13 @@ def OMP_TargetUpdate : Directive<"target update"> { VersionedClause<OMPC_If>, VersionedClause<OMPC_NoWait> ]; + let association = AS_None; +} +def OMP_masked : Directive<"masked"> { + let allowedOnceClauses = [ + VersionedClause<OMPC_Filter> + ]; + let association = AS_Block; } def OMP_ParallelFor : Directive<"parallel for"> { let allowedClauses = [ @@ -866,6 +912,7 @@ def OMP_ParallelFor : Directive<"parallel for"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_For]; } def OMP_ParallelDo : Directive<"parallel do"> { let allowedClauses = [ @@ -887,6 +934,7 @@ def OMP_ParallelDo : Directive<"parallel do"> { VersionedClause<OMPC_Collapse>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Parallel, OMP_Do]; } def OMP_ParallelForSimd : Directive<"parallel for simd"> { let allowedClauses = [ @@ -912,6 +960,7 @@ def OMP_ParallelForSimd : Directive<"parallel for simd"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_For, OMP_Simd]; } def OMP_ParallelDoSimd : Directive<"parallel do simd"> { let allowedClauses = [ @@ -938,6 +987,7 @@ def OMP_ParallelDoSimd : Directive<"parallel do simd"> { VersionedClause<OMPC_SimdLen>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Parallel, OMP_Do, OMP_Simd]; } def OMP_ParallelMaster : Directive<"parallel master"> { let allowedClauses = [ @@ -953,6 +1003,7 @@ def OMP_ParallelMaster : Directive<"parallel master"> { VersionedClause<OMPC_Allocate>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_Master]; } def OMP_ParallelMasked : Directive<"parallel masked"> { let allowedClauses = [ @@ -969,6 +1020,7 @@ def OMP_ParallelMasked : Directive<"parallel masked"> { VersionedClause<OMPC_Filter>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_masked]; } def OMP_ParallelSections : Directive<"parallel sections"> { let allowedClauses = [ @@ -987,6 +1039,7 @@ def OMP_ParallelSections : Directive<"parallel sections"> { VersionedClause<OMPC_If>, VersionedClause<OMPC_NumThreads> ]; + let leafConstructs = [OMP_Parallel, OMP_Sections]; } def OMP_ForSimd : Directive<"for simd"> { let allowedClauses = [ @@ -1007,6 +1060,7 @@ def OMP_ForSimd : Directive<"for simd"> { VersionedClause<OMPC_NonTemporal, 50>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_For, OMP_Simd]; } def OMP_DoSimd : Directive<"do simd"> { let allowedClauses = [ @@ -1027,13 +1081,19 @@ def OMP_DoSimd : Directive<"do simd"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Do, OMP_Simd]; +} +def OMP_CancellationPoint : Directive<"cancellation point"> { + let association = AS_None; +} +def OMP_DeclareReduction : Directive<"declare reduction"> { + let association = AS_None; } -def OMP_CancellationPoint : Directive<"cancellation point"> {} -def OMP_DeclareReduction : Directive<"declare reduction"> {} def OMP_DeclareMapper : Directive<"declare mapper"> { let allowedClauses = [ VersionedClause<OMPC_Map> ]; + let association = AS_None; } def OMP_DeclareSimd : Directive<"declare simd"> { let allowedClauses = [ @@ -1048,6 +1108,7 @@ def OMP_DeclareSimd : Directive<"declare simd"> { VersionedClause<OMPC_Inbranch>, VersionedClause<OMPC_Notinbranch> ]; + let association = AS_Declaration; } def OMP_TaskLoop : Directive<"taskloop"> { let allowedClauses = [ @@ -1073,6 +1134,7 @@ def OMP_TaskLoop : Directive<"taskloop"> { VersionedClause<OMPC_GrainSize>, VersionedClause<OMPC_NumTasks> ]; + let association = AS_Loop; } def OMP_TaskLoopSimd : Directive<"taskloop simd"> { let allowedClauses = [ @@ -1104,6 +1166,7 @@ def OMP_TaskLoopSimd : Directive<"taskloop simd"> { VersionedClause<OMPC_GrainSize>, VersionedClause<OMPC_NumTasks> ]; + let leafConstructs = [OMP_TaskLoop, OMP_Simd]; } def OMP_Distribute : Directive<"distribute"> { let allowedClauses = [ @@ -1116,6 +1179,7 @@ def OMP_Distribute : Directive<"distribute"> { VersionedClause<OMPC_Collapse>, VersionedClause<OMPC_DistSchedule> ]; + let association = AS_Loop; } def OMP_BeginDeclareTarget : Directive<"begin declare target"> { let allowedClauses = [ @@ -1124,6 +1188,7 @@ def OMP_BeginDeclareTarget : Directive<"begin declare target"> { VersionedClause<OMPC_DeviceType>, VersionedClause<OMPC_Indirect> ]; + let association = AS_Delimited; } def OMP_DeclareTarget : Directive<"declare target"> { let allowedClauses = [ @@ -1135,8 +1200,11 @@ def OMP_DeclareTarget : Directive<"declare target"> { let allowedOnceClauses = [ VersionedClause<OMPC_DeviceType, 50> ]; + let association = AS_None; +} +def OMP_EndDeclareTarget : Directive<"end declare target"> { + let association = AS_Delimited; } -def OMP_EndDeclareTarget : Directive<"end declare target"> {} def OMP_DistributeParallelFor : Directive<"distribute parallel for"> { let allowedClauses = [ VersionedClause<OMPC_FirstPrivate>, @@ -1156,6 +1224,7 @@ def OMP_DistributeParallelFor : Directive<"distribute parallel for"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Distribute, OMP_Parallel, OMP_For]; } def OMP_DistributeParallelDo : Directive<"distribute parallel do"> { let allowedClauses = [ @@ -1179,6 +1248,7 @@ def OMP_DistributeParallelDo : Directive<"distribute parallel do"> { VersionedClause<OMPC_Ordered>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Distribute, OMP_Parallel, OMP_Do]; } def OMP_DistributeParallelForSimd : Directive<"distribute parallel for simd"> { let allowedClauses = [ @@ -1204,6 +1274,7 @@ def OMP_DistributeParallelForSimd : Directive<"distribute parallel for simd"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Distribute, OMP_Parallel, OMP_For, OMP_Simd]; } def OMP_DistributeParallelDoSimd : Directive<"distribute parallel do simd"> { let allowedClauses = [ @@ -1228,6 +1299,7 @@ def OMP_DistributeParallelDoSimd : Directive<"distribute parallel do simd"> { VersionedClause<OMPC_NonTemporal>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Distribute, OMP_Parallel, OMP_Do, OMP_Simd]; } def OMP_DistributeSimd : Directive<"distribute simd"> { let allowedClauses = [ @@ -1254,6 +1326,7 @@ def OMP_DistributeSimd : Directive<"distribute simd"> { VersionedClause<OMPC_SimdLen>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Distribute, OMP_Simd]; } def OMP_TargetParallelForSimd : Directive<"target parallel for simd"> { @@ -1291,6 +1364,7 @@ def OMP_TargetParallelForSimd : Directive<"target parallel for simd"> { VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_ThreadLimit, 51>, ]; + let leafConstructs = [OMP_Target, OMP_Parallel, OMP_For, OMP_Simd]; } def OMP_TargetParallelDoSimd : Directive<"target parallel do simd"> { let allowedClauses = [ @@ -1322,6 +1396,7 @@ def OMP_TargetParallelDoSimd : Directive<"target parallel do simd"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_UsesAllocators> ]; + let leafConstructs = [OMP_Target, OMP_Parallel, OMP_Do, OMP_Simd]; } def OMP_TargetSimd : Directive<"target simd"> { let allowedClauses = [ @@ -1356,6 +1431,7 @@ def OMP_TargetSimd : Directive<"target simd"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_ThreadLimit, 51>, ]; + let leafConstructs = [OMP_Target, OMP_Simd]; } def OMP_TeamsDistribute : Directive<"teams distribute"> { let allowedClauses = [ @@ -1375,6 +1451,7 @@ def OMP_TeamsDistribute : Directive<"teams distribute"> { let allowedOnceClauses = [ VersionedClause<OMPC_If> ]; + let leafConstructs = [OMP_Teams, OMP_Distribute]; } def OMP_TeamsDistributeSimd : Directive<"teams distribute simd"> { let allowedClauses = [ @@ -1400,6 +1477,7 @@ def OMP_TeamsDistributeSimd : Directive<"teams distribute simd"> { VersionedClause<OMPC_ThreadLimit>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Simd]; } def OMP_TeamsDistributeParallelForSimd : @@ -1428,6 +1506,7 @@ def OMP_TeamsDistributeParallelForSimd : VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For, OMP_Simd]; } def OMP_TeamsDistributeParallelDoSimd : Directive<"teams distribute parallel do simd"> { @@ -1456,6 +1535,7 @@ def OMP_TeamsDistributeParallelDoSimd : VersionedClause<OMPC_SimdLen>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_Do, OMP_Simd]; } def OMP_TeamsDistributeParallelFor : Directive<"teams distribute parallel for"> { @@ -1479,6 +1559,7 @@ def OMP_TeamsDistributeParallelFor : VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For]; } def OMP_TeamsDistributeParallelDo : Directive<"teams distribute parallel do"> { @@ -1505,6 +1586,7 @@ let allowedOnceClauses = [ VersionedClause<OMPC_Schedule>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_Do]; } def OMP_TargetTeams : Directive<"target teams"> { let allowedClauses = [ @@ -1532,6 +1614,7 @@ def OMP_TargetTeams : Directive<"target teams"> { VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_OMX_Bare>, ]; + let leafConstructs = [OMP_Target, OMP_Teams]; } def OMP_TargetTeamsDistribute : Directive<"target teams distribute"> { let allowedClauses = [ @@ -1560,6 +1643,7 @@ def OMP_TargetTeamsDistribute : Directive<"target teams distribute"> { VersionedClause<OMPC_DistSchedule>, VersionedClause<OMPC_OMPX_DynCGroupMem>, ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute]; } def OMP_TargetTeamsDistributeParallelFor : @@ -1594,6 +1678,7 @@ def OMP_TargetTeamsDistributeParallelFor : let allowedOnceClauses = [ VersionedClause<OMPC_OMPX_DynCGroupMem>, ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For]; } def OMP_TargetTeamsDistributeParallelDo : Directive<"target teams distribute parallel do"> { @@ -1628,6 +1713,7 @@ def OMP_TargetTeamsDistributeParallelDo : VersionedClause<OMPC_Schedule>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_Do]; } def OMP_TargetTeamsDistributeParallelForSimd : Directive<"target teams distribute parallel for simd"> { @@ -1666,6 +1752,7 @@ def OMP_TargetTeamsDistributeParallelForSimd : let allowedOnceClauses = [ VersionedClause<OMPC_OMPX_DynCGroupMem>, ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_For, OMP_Simd]; } def OMP_TargetTeamsDistributeParallelDoSimd : Directive<"target teams distribute parallel do simd"> { @@ -1704,6 +1791,7 @@ def OMP_TargetTeamsDistributeParallelDoSimd : VersionedClause<OMPC_SimdLen>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Parallel, OMP_Do, OMP_Simd]; } def OMP_TargetTeamsDistributeSimd : Directive<"target teams distribute simd"> { @@ -1738,17 +1826,20 @@ def OMP_TargetTeamsDistributeSimd : VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_Distribute, OMP_Simd]; } def OMP_Allocate : Directive<"allocate"> { let allowedOnceClauses = [ VersionedClause<OMPC_Allocator>, VersionedClause<OMPC_Align, 51> ]; + let association = AS_None; } def OMP_Allocators : Directive<"allocators"> { let allowedClauses = [ VersionedClause<OMPC_Allocate> ]; + let association = AS_Block; } def OMP_DeclareVariant : Directive<"declare variant"> { let allowedClauses = [ @@ -1758,6 +1849,7 @@ def OMP_DeclareVariant : Directive<"declare variant"> { VersionedClause<OMPC_AdjustArgs, 51>, VersionedClause<OMPC_AppendArgs, 51> ]; + let association = AS_Declaration; } def OMP_MasterTaskloop : Directive<"master taskloop"> { let allowedClauses = [ @@ -1779,6 +1871,7 @@ def OMP_MasterTaskloop : Directive<"master taskloop"> { VersionedClause<OMPC_InReduction>, VersionedClause<OMPC_Allocate> ]; + let leafConstructs = [OMP_Master, OMP_TaskLoop]; } def OMP_MaskedTaskloop : Directive<"masked taskloop"> { let allowedClauses = [ @@ -1801,6 +1894,7 @@ def OMP_MaskedTaskloop : Directive<"masked taskloop"> { VersionedClause<OMPC_Allocate>, VersionedClause<OMPC_Filter> ]; + let leafConstructs = [OMP_masked, OMP_TaskLoop]; } def OMP_ParallelMasterTaskloop : Directive<"parallel master taskloop"> { @@ -1826,6 +1920,7 @@ def OMP_ParallelMasterTaskloop : VersionedClause<OMPC_Copyin>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_Master, OMP_TaskLoop]; } def OMP_ParallelMaskedTaskloop : Directive<"parallel masked taskloop"> { @@ -1852,6 +1947,7 @@ def OMP_ParallelMaskedTaskloop : VersionedClause<OMPC_Filter>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_masked, OMP_TaskLoop]; } def OMP_MasterTaskloopSimd : Directive<"master taskloop simd"> { let allowedClauses = [ @@ -1879,6 +1975,7 @@ def OMP_MasterTaskloopSimd : Directive<"master taskloop simd"> { VersionedClause<OMPC_NonTemporal, 50>, VersionedClause<OMPC_Order, 50> ]; + let leafConstructs = [OMP_Master, OMP_TaskLoop, OMP_Simd]; } def OMP_MaskedTaskloopSimd : Directive<"masked taskloop simd"> { let allowedClauses = [ @@ -1907,6 +2004,7 @@ def OMP_MaskedTaskloopSimd : Directive<"masked taskloop simd"> { VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_Filter> ]; + let leafConstructs = [OMP_masked, OMP_TaskLoop, OMP_Simd]; } def OMP_ParallelMasterTaskloopSimd : Directive<"parallel master taskloop simd"> { @@ -1938,6 +2036,7 @@ def OMP_ParallelMasterTaskloopSimd : VersionedClause<OMPC_Order, 50>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_Master, OMP_TaskLoop, OMP_Simd]; } def OMP_ParallelMaskedTaskloopSimd : Directive<"parallel masked taskloop simd"> { @@ -1970,6 +2069,7 @@ def OMP_ParallelMaskedTaskloopSimd : VersionedClause<OMPC_Filter>, VersionedClause<OMPC_OMPX_Attribute>, ]; + let leafConstructs = [OMP_Parallel, OMP_masked, OMP_TaskLoop, OMP_Simd]; } def OMP_Depobj : Directive<"depobj"> { let allowedClauses = [ @@ -1980,18 +2080,30 @@ def OMP_Depobj : Directive<"depobj"> { // OMPKinds.def. VersionedClause<OMPC_Depobj, 50> ]; + let association = AS_None; } def OMP_Scan : Directive<"scan"> { let allowedClauses = [ VersionedClause<OMPC_Inclusive, 50>, VersionedClause<OMPC_Exclusive, 50> ]; + let association = AS_Separating; +} +def OMP_Assumes : Directive<"assumes"> { + let association = AS_None; +} +def OMP_BeginAssumes : Directive<"begin assumes"> { + let association = AS_Delimited; +} +def OMP_EndAssumes : Directive<"end assumes"> { + let association = AS_Delimited; +} +def OMP_BeginDeclareVariant : Directive<"begin declare variant"> { + let association = AS_Delimited; +} +def OMP_EndDeclareVariant : Directive<"end declare variant"> { + let association = AS_Delimited; } -def OMP_Assumes : Directive<"assumes"> {} -def OMP_BeginAssumes : Directive<"begin assumes"> {} -def OMP_EndAssumes : Directive<"end assumes"> {} -def OMP_BeginDeclareVariant : Directive<"begin declare variant"> {} -def OMP_EndDeclareVariant : Directive<"end declare variant"> {} def OMP_scope : Directive<"scope"> { let allowedClauses = [ VersionedClause<OMPC_Private, 51>, @@ -2000,6 +2112,10 @@ def OMP_scope : Directive<"scope"> { let allowedOnceClauses = [ VersionedClause<OMPC_NoWait, 51> ]; + let association = AS_Block; +} +def OMP_Workshare : Directive<"workshare"> { + let association = AS_Block; } def OMP_ParallelWorkshare : Directive<"parallel workshare"> { let allowedClauses = [ @@ -2016,22 +2132,29 @@ def OMP_ParallelWorkshare : Directive<"parallel workshare"> { VersionedClause<OMPC_NumThreads>, VersionedClause<OMPC_ProcBind> ]; + let leafConstructs = [OMP_Parallel, OMP_Workshare]; } -def OMP_Workshare : Directive<"workshare"> {} def OMP_EndDo : Directive<"end do"> { let allowedOnceClauses = [ VersionedClause<OMPC_NoWait> ]; + // Needed for association computation, since OMP_Do has it "from leafConstructs". + let leafConstructs = OMP_Do.leafConstructs; + let association = OMP_Do.association; } def OMP_EndDoSimd : Directive<"end do simd"> { let allowedOnceClauses = [ VersionedClause<OMPC_NoWait> ]; + let leafConstructs = OMP_DoSimd.leafConstructs; + let association = OMP_DoSimd.association; } def OMP_EndSections : Directive<"end sections"> { let allowedOnceClauses = [ VersionedClause<OMPC_NoWait> ]; + let leafConstructs = OMP_Sections.leafConstructs; + let association = OMP_Sections.association; } def OMP_EndSingle : Directive<"end single"> { let allowedClauses = [ @@ -2040,11 +2163,15 @@ def OMP_EndSingle : Directive<"end single"> { let allowedOnceClauses = [ VersionedClause<OMPC_NoWait> ]; + let leafConstructs = OMP_Single.leafConstructs; + let association = OMP_Single.association; } def OMP_EndWorkshare : Directive<"end workshare"> { let allowedClauses = [ VersionedClause<OMPC_NoWait> ]; + let leafConstructs = OMP_Workshare.leafConstructs; + let association = OMP_Workshare.association; } def OMP_interop : Directive<"interop"> { let allowedClauses = [ @@ -2055,6 +2182,7 @@ def OMP_interop : Directive<"interop"> { VersionedClause<OMPC_NoWait>, VersionedClause<OMPC_Use>, ]; + let association = AS_None; } def OMP_dispatch : Directive<"dispatch"> { let allowedClauses = [ @@ -2066,11 +2194,7 @@ def OMP_dispatch : Directive<"dispatch"> { VersionedClause<OMPC_Novariants>, VersionedClause<OMPC_Nocontext> ]; -} -def OMP_masked : Directive<"masked"> { - let allowedOnceClauses = [ - VersionedClause<OMPC_Filter> - ]; + let association = AS_Block; } def OMP_loop : Directive<"loop"> { let allowedClauses = [ @@ -2083,6 +2207,7 @@ def OMP_loop : Directive<"loop"> { VersionedClause<OMPC_Collapse>, VersionedClause<OMPC_Order, 50> ]; + let association = AS_Loop; } def OMP_teams_loop : Directive<"teams loop"> { let allowedClauses = [ @@ -2102,6 +2227,7 @@ def OMP_teams_loop : Directive<"teams loop"> { VersionedClause<OMPC_Order>, VersionedClause<OMPC_ThreadLimit>, ]; + let leafConstructs = [OMP_Teams, OMP_loop]; } def OMP_target_teams_loop : Directive<"target teams loop"> { let allowedClauses = [ @@ -2131,6 +2257,7 @@ def OMP_target_teams_loop : Directive<"target teams loop"> { VersionedClause<OMPC_ThreadLimit>, VersionedClause<OMPC_OMPX_DynCGroupMem>, ]; + let leafConstructs = [OMP_Target, OMP_Teams, OMP_loop]; } def OMP_parallel_loop : Directive<"parallel loop"> { let allowedClauses = [ @@ -2152,6 +2279,7 @@ def OMP_parallel_loop : Directive<"parallel loop"> { VersionedClause<OMPC_Order>, VersionedClause<OMPC_ProcBind>, ]; + let leafConstructs = [OMP_Parallel, OMP_loop]; } def OMP_target_parallel_loop : Directive<"target parallel loop"> { let allowedClauses = [ @@ -2183,11 +2311,15 @@ def OMP_target_parallel_loop : Directive<"target parallel loop"> { VersionedClause<OMPC_OMPX_DynCGroupMem>, VersionedClause<OMPC_ThreadLimit, 51>, ]; + let leafConstructs = [OMP_Target, OMP_Parallel, OMP_loop]; } def OMP_Metadirective : Directive<"metadirective"> { let allowedClauses = [VersionedClause<OMPC_When>]; let allowedOnceClauses = [VersionedClause<OMPC_Default>]; + let association = AS_None; } + def OMP_Unknown : Directive<"unknown"> { let isDefault = true; + let association = AS_None; } diff --git a/llvm/include/llvm/TableGen/DirectiveEmitter.h b/llvm/include/llvm/TableGen/DirectiveEmitter.h index c86018715a48a1..bd536d4a2b7f8c 100644 --- a/llvm/include/llvm/TableGen/DirectiveEmitter.h +++ b/llvm/include/llvm/TableGen/DirectiveEmitter.h @@ -51,6 +51,10 @@ class DirectiveLanguage { return Def->getValueAsBit("enableBitmaskEnumInNamespace"); } + std::vector<Record *> getAssociations() const { + return Records.getAllDerivedDefinitions("Association"); + } + std::vector<Record *> getDirectives() const { return Records.getAllDerivedDefinitions("Directive"); } @@ -121,6 +125,12 @@ class Directive : public BaseRecord { std::vector<Record *> getRequiredClauses() const { return Def->getValueAsListOfDefs("requiredClauses"); } + + std::vector<Record *> getLeafConstructs() const { + return Def->getValueAsListOfDefs("leafConstructs"); + } + + Record *getAssociation() const { return Def->getValueAsDef("association"); } }; // Wrapper class that contains Clause's information defined in DirectiveBase.td diff --git a/llvm/test/TableGen/directive1.td b/llvm/test/TableGen/directive1.td index bcd9fa34c99d3a..aa47d7ee666d02 100644 --- a/llvm/test/TableGen/directive1.td +++ b/llvm/test/TableGen/directive1.td @@ -44,11 +44,13 @@ def TDL_DirA : Directive<"dira"> { VersionedClause<TDLC_ClauseB> ]; let isDefault = 1; + let association = AS_None; } // CHECK: #ifndef LLVM_Tdl_INC // CHECK-NEXT: #define LLVM_Tdl_INC // CHECK-EMPTY: +// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h" // CHECK-NEXT: #include "llvm/ADT/BitmaskEnum.h" // CHECK-EMPTY: // CHECK-NEXT: namespace llvm { @@ -57,6 +59,17 @@ def TDL_DirA : Directive<"dira"> { // CHECK-EMPTY: // CHECK-NEXT: LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE(); // CHECK-EMPTY: +// CHECK-NEXT: enum class Association { +// CHECK-NEXT: Block, +// CHECK-NEXT: Declaration, +// CHECK-NEXT: Delimited, +// CHECK-NEXT: Loop, +// CHECK-NEXT: None, +// CHECK-NEXT: Separating, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Association_enumSize = 6; +// CHECK-EMPTY: // CHECK-NEXT: enum class Directive { // CHECK-NEXT: TDLD_dira, // CHECK-NEXT: }; @@ -99,6 +112,8 @@ def TDL_DirA : Directive<"dira"> { // CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version. // CHECK-NEXT: bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); // CHECK-EMPTY: +// CHECK-NEXT: llvm::ArrayRef<Directive> getLeafConstructs(Directive D); +// CHECK-NEXT: Association getDirectiveAssociation(Directive D); // CHECK-NEXT: AKind getAKind(StringRef); // CHECK-NEXT: llvm::StringRef getTdlAKindName(AKind); // CHECK-EMPTY: @@ -270,6 +285,8 @@ def TDL_DirA : Directive<"dira"> { // IMPL: #ifdef GEN_DIRECTIVES_IMPL // IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL // IMPL-EMPTY: +// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" +// IMPL-EMPTY: // IMPL-NEXT: Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) { // IMPL-NEXT: return llvm::StringSwitch<Directive>(Str) // IMPL-NEXT: .Case("dira",TDLD_dira) @@ -342,4 +359,20 @@ def TDL_DirA : Directive<"dira"> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: +// IMPL-NEXT: llvm::ArrayRef<llvm::tdl::Directive> llvm::tdl::getLeafConstructs(llvm::tdl::Directive Dir) { +// IMPL-NEXT: switch (Dir) { +// IMPL-NEXT: default: +// IMPL-NEXT: return ArrayRef<llvm::tdl::Directive>{}; +// IMPL-NEXT: } // switch (Dir) +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::tdl::Association llvm::tdl::getDirectiveAssociation(llvm::tdl::Directive Dir) { +// IMPL-NEXT: switch (Dir) { +// IMPL-NEXT: case llvm::tdl::Directive::TDLD_dira: +// IMPL-NEXT: return llvm::tdl::Association::None; +// IMPL-NEXT: default: +// IMPL-NEXT: llvm_unreachable("Unexpected directive"); +// IMPL-NEXT: } // switch(Dir) +// IMPL-NEXT: } +// IMPL-EMPTY: // IMPL-NEXT: #endif // GEN_DIRECTIVES_IMPL diff --git a/llvm/test/TableGen/directive2.td b/llvm/test/TableGen/directive2.td index 01741152956d22..90f9c45b5e15bd 100644 --- a/llvm/test/TableGen/directive2.td +++ b/llvm/test/TableGen/directive2.td @@ -38,15 +38,29 @@ def TDL_DirA : Directive<"dira"> { VersionedClause<TDLC_ClauseB, 2> ]; let isDefault = 1; + let association = AS_Block; } // CHECK: #ifndef LLVM_Tdl_INC // CHECK-NEXT: #define LLVM_Tdl_INC // CHECK-EMPTY: +// CHECK-NEXT: #include "llvm/ADT/ArrayRef.h" +// CHECK-EMPTY: // CHECK-NEXT: namespace llvm { // CHECK-NEXT: class StringRef; // CHECK-NEXT: namespace tdl { // CHECK-EMPTY: +// CHECK-NEXT: enum class Association { +// CHECK-NEXT: Block, +// CHECK-NEXT: Declaration, +// CHECK-NEXT: Delimited, +// CHECK-NEXT: Loop, +// CHECK-NEXT: None, +// CHECK-NEXT: Separating, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr std::size_t Association_enumSize = 6; +// CHECK-EMPTY: // CHECK-NEXT: enum class Directive { // CHECK-NEXT: TDLD_dira, // CHECK-NEXT: }; @@ -74,6 +88,8 @@ def TDL_DirA : Directive<"dira"> { // CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version. // CHECK-NEXT: bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version); // CHECK-EMPTY: +// CHECK-NEXT: llvm::ArrayRef<Directive> getLeafConstructs(Directive D); +// CHECK-NEXT: Association getDirectiveAssociation(Directive D); // CHECK-NEXT: } // namespace tdl // CHECK-NEXT: } // namespace llvm // CHECK-NEXT: #endif // LLVM_Tdl_INC @@ -217,6 +233,8 @@ def TDL_DirA : Directive<"dira"> { // IMPL: #ifdef GEN_DIRECTIVES_IMPL // IMPL-NEXT: #undef GEN_DIRECTIVES_IMPL // IMPL-EMPTY: +// IMPL-NEXT: #include "llvm/Support/ErrorHandling.h" +// IMPL-EMPTY: // IMPL-NEXT: Directive llvm::tdl::getTdlDirectiveKind(llvm::StringRef Str) { // IMPL-NEXT: return llvm::StringSwitch<Directive>(Str) // IMPL-NEXT: .Case("dira",TDLD_dira) @@ -272,4 +290,20 @@ def TDL_DirA : Directive<"dira"> { // IMPL-NEXT: llvm_unreachable("Invalid Tdl Directive kind"); // IMPL-NEXT: } // IMPL-EMPTY: +// IMPL-NEXT: llvm::ArrayRef<llvm::tdl::Directive> llvm::tdl::getLeafConstructs(llvm::tdl::Directive Dir) { +// IMPL-NEXT: switch (Dir) { +// IMPL-NEXT: default: +// IMPL-NEXT: return ArrayRef<llvm::tdl::Directive>{}; +// IMPL-NEXT: } // switch (Dir) +// IMPL-NEXT: } +// IMPL-EMPTY: +// IMPL-NEXT: llvm::tdl::Association llvm::tdl::getDirectiveAssociation(llvm::tdl::Directive Dir) { +// IMPL-NEXT: switch (Dir) { +// IMPL-NEXT: case llvm::tdl::Directive::TDLD_dira: +// IMPL-NEXT: return llvm::tdl::Association::Block; +// IMPL-NEXT: default: +// IMPL-NEXT: llvm_unreachable("Unexpected directive"); +// IMPL-NEXT: } // switch(Dir) +// IMPL-NEXT: } +// IMPL-EMPTY: // IMPL-NEXT: #endif // GEN_DIRECTIVES_IMPL diff --git a/llvm/utils/TableGen/DirectiveEmitter.cpp b/llvm/utils/TableGen/DirectiveEmitter.cpp index 99eebacd6b3f32..5a35d320227d5b 100644 --- a/llvm/utils/TableGen/DirectiveEmitter.cpp +++ b/llvm/utils/TableGen/DirectiveEmitter.cpp @@ -42,7 +42,8 @@ class IfDefScope { // Generate enum class static void GenerateEnumClass(const std::vector<Record *> &Records, raw_ostream &OS, StringRef Enum, StringRef Prefix, - const DirectiveLanguage &DirLang) { + const DirectiveLanguage &DirLang, + bool ExportEnums) { OS << "\n"; OS << "enum class " << Enum << " {\n"; for (const auto &R : Records) { @@ -59,7 +60,7 @@ static void GenerateEnumClass(const std::vector<Record *> &Records, // At the same time we do not loose the strong type guarantees of the enum // class, that is we cannot pass an unsigned as Directive without an explicit // cast. - if (DirLang.hasMakeEnumAvailableInNamespace()) { + if (ExportEnums) { OS << "\n"; for (const auto &R : Records) { BaseRecord Rec{R}; @@ -183,9 +184,10 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { OS << "#ifndef LLVM_" << DirLang.getName() << "_INC\n"; OS << "#define LLVM_" << DirLang.getName() << "_INC\n"; + OS << "\n#include \"llvm/ADT/ArrayRef.h\"\n"; if (DirLang.hasEnableBitmaskEnumInNamespace()) - OS << "\n#include \"llvm/ADT/BitmaskEnum.h\"\n"; + OS << "#include \"llvm/ADT/BitmaskEnum.h\"\n"; OS << "\n"; OS << "namespace llvm {\n"; @@ -200,13 +202,24 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { if (DirLang.hasEnableBitmaskEnumInNamespace()) OS << "\nLLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();\n"; + // Emit Directive associations + std::vector<Record *> associations; + llvm::copy_if( + DirLang.getAssociations(), std::back_inserter(associations), + // Skip the "special" value + [](const Record *Def) { return Def->getName() != "AS_FromLeaves"; }); + GenerateEnumClass(associations, OS, "Association", + /*Prefix=*/"", DirLang, /*ExportEnums=*/false); + // Emit Directive enumeration GenerateEnumClass(DirLang.getDirectives(), OS, "Directive", - DirLang.getDirectivePrefix(), DirLang); + DirLang.getDirectivePrefix(), DirLang, + DirLang.hasMakeEnumAvailableInNamespace()); // Emit Clause enumeration GenerateEnumClass(DirLang.getClauses(), OS, "Clause", - DirLang.getClausePrefix(), DirLang); + DirLang.getClausePrefix(), DirLang, + DirLang.hasMakeEnumAvailableInNamespace()); // Emit ClauseVal enumeration std::string EnumHelperFuncs; @@ -231,6 +244,8 @@ static void EmitDirectivesDecl(RecordKeeper &Records, raw_ostream &OS) { OS << "bool isAllowedClauseForDirective(Directive D, " << "Clause C, unsigned Version);\n"; OS << "\n"; + OS << "llvm::ArrayRef<Directive> getLeafConstructs(Directive D);\n"; + OS << "Association getDirectiveAssociation(Directive D);\n"; if (EnumHelperFuncs.length() > 0) { OS << EnumHelperFuncs; OS << "\n"; @@ -435,6 +450,217 @@ static void GenerateIsAllowedClause(const DirectiveLanguage &DirLang, OS << "}\n"; // End of function isAllowedClauseForDirective } +// Generate the getLeafConstructs function implementation. +static void GenerateGetLeafConstructs(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + auto getQualifiedName = [&](StringRef Formatted) -> std::string { + return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + + "::Directive::" + DirLang.getDirectivePrefix() + Formatted) + .str(); + }; + + // For each list of leaves, generate a static local object, then + // return a reference to that object for a given directive, e.g. + // + // static ListTy leafConstructs_A_B = { A, B }; + // static ListTy leafConstructs_C_D_E = { C, D, E }; + // switch (Dir) { + // case A_B: + // return leafConstructs_A_B; + // case C_D_E: + // return leafConstructs_C_D_E; + // } + + // Map from a record that defines a directive to the name of the + // local object with the list of its leaves. + DenseMap<Record *, std::string> ListNames; + + std::string DirectiveTypeName = + std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive"; + + OS << '\n'; + + // ArrayRef<...> llvm::<ns>::GetLeafConstructs(llvm::<ns>::Directive Dir) + OS << "llvm::ArrayRef<" << DirectiveTypeName + << "> llvm::" << DirLang.getCppNamespace() << "::getLeafConstructs(" + << DirectiveTypeName << " Dir) "; + OS << "{\n"; + + // Generate the locals. + for (Record *R : DirLang.getDirectives()) { + Directive Dir{R}; + + std::vector<Record *> LeafConstructs = Dir.getLeafConstructs(); + if (LeafConstructs.empty()) + continue; + + std::string ListName = "leafConstructs_" + Dir.getFormattedName(); + OS << " static const " << DirectiveTypeName << ' ' << ListName + << "[] = {\n"; + for (Record *L : LeafConstructs) { + Directive LeafDir{L}; + OS << " " << getQualifiedName(LeafDir.getFormattedName()) << ",\n"; + } + OS << " };\n"; + ListNames.insert(std::make_pair(R, std::move(ListName))); + } + + if (!ListNames.empty()) + OS << '\n'; + OS << " switch (Dir) {\n"; + for (Record *R : DirLang.getDirectives()) { + auto F = ListNames.find(R); + if (F == ListNames.end()) + continue; + + Directive Dir{R}; + OS << " case " << getQualifiedName(Dir.getFormattedName()) << ":\n"; + OS << " return " << F->second << ";\n"; + } + OS << " default:\n"; + OS << " return ArrayRef<" << DirectiveTypeName << ">{};\n"; + OS << " } // switch (Dir)\n"; + OS << "}\n"; +} + +static void GenerateGetDirectiveAssociation(const DirectiveLanguage &DirLang, + raw_ostream &OS) { + enum struct Association { + None = 0, // None should be the smallest value. + Block, // The values of the rest don't matter. + Declaration, + Delimited, + Loop, + Separating, + FromLeaves, + Invalid, + }; + + std::vector<Record *> associations = DirLang.getAssociations(); + + auto getAssocValue = [](StringRef name) -> Association { + return StringSwitch<Association>(name) + .Case("AS_Block", Association::Block) + .Case("AS_Declaration", Association::Declaration) + .Case("AS_Delimited", Association::Delimited) + .Case("AS_Loop", Association::Loop) + .Case("AS_None", Association::None) + .Case("AS_Separating", Association::Separating) + .Case("AS_FromLeaves", Association::FromLeaves) + .Default(Association::Invalid); + }; + + auto getAssocName = [&](Association A) -> StringRef { + if (A != Association::Invalid && A != Association::FromLeaves) { + auto F = llvm::find_if(associations, [&](const Record *R) { + return getAssocValue(R->getName()) == A; + }); + if (F != associations.end()) + return (*F)->getValueAsString("name"); // enum name + } + llvm_unreachable("Unexpected association value"); + }; + + auto errorPrefixFor = [&](Directive D) -> std::string { + return (Twine("Directive '") + D.getName() + "' in namespace '" + + DirLang.getCppNamespace() + "' ") + .str(); + }; + + auto reduce = [&](Association A, Association B) -> Association { + if (A > B) + std::swap(A, B); + + // Calculate the result using the following rules: + // x + x = x + // AS_None + x = x + // AS_Block + AS_Loop = AS_Loop + if (A == Association::None || A == B) + return B; + if (A == Association::Block && B == Association::Loop) + return B; + if (A == Association::Loop && B == Association::Block) + return A; + return Association::Invalid; + }; + + llvm::DenseMap<const Record *, Association> AsMap; + + auto compAssocImpl = [&](const Record *R, auto &&Self) -> Association { + if (auto F = AsMap.find(R); F != AsMap.end()) + return F->second; + + Directive D{R}; + Association AS = getAssocValue(D.getAssociation()->getName()); + if (AS == Association::Invalid) { + PrintFatalError(errorPrefixFor(D) + + "has an unrecognized value for association: '" + + D.getAssociation()->getName() + "'"); + } + if (AS != Association::FromLeaves) { + AsMap.insert(std::make_pair(R, AS)); + return AS; + } + // Compute the association from leaf constructs. + std::vector<Record *> leaves = D.getLeafConstructs(); + if (leaves.empty()) { + llvm::errs() << D.getName() << '\n'; + PrintFatalError(errorPrefixFor(D) + + "requests association to be computed from leaves, " + "but it has no leaves"); + } + + Association Result = Self(leaves[0], Self); + for (int I = 1, E = leaves.size(); I < E; ++I) { + Association A = Self(leaves[I], Self); + Association R = reduce(Result, A); + if (R == Association::Invalid) { + PrintFatalError(errorPrefixFor(D) + + "has leaves with incompatible association values: " + + getAssocName(A) + " and " + getAssocName(R)); + } + Result = R; + } + + assert(Result != Association::Invalid); + assert(Result != Association::FromLeaves); + AsMap.insert(std::make_pair(R, Result)); + return Result; + }; + + for (Record *R : DirLang.getDirectives()) + compAssocImpl(R, compAssocImpl); // Updates AsMap. + + OS << '\n'; + + auto getQualifiedName = [&](StringRef Formatted) -> std::string { + return (llvm::Twine("llvm::") + DirLang.getCppNamespace() + + "::Directive::" + DirLang.getDirectivePrefix() + Formatted) + .str(); + }; + + std::string DirectiveTypeName = + std::string("llvm::") + DirLang.getCppNamespace().str() + "::Directive"; + std::string AssociationTypeName = + std::string("llvm::") + DirLang.getCppNamespace().str() + "::Association"; + + OS << AssociationTypeName << " llvm::" << DirLang.getCppNamespace() + << "::getDirectiveAssociation(" << DirectiveTypeName << " Dir) {\n"; + OS << " switch (Dir) {\n"; + for (Record *R : DirLang.getDirectives()) { + if (auto F = AsMap.find(R); F != AsMap.end()) { + Directive Dir{R}; + OS << " case " << getQualifiedName(Dir.getFormattedName()) << ":\n"; + OS << " return " << AssociationTypeName + << "::" << getAssocName(F->second) << ";\n"; + } + } + OS << " default:\n"; + OS << " llvm_unreachable(\"Unexpected directive\");\n"; + OS << " } // switch(Dir)\n"; + OS << "}\n"; +} + // Generate a simple enum set with the give clauses. static void GenerateClauseSet(const std::vector<Record *> &Clauses, raw_ostream &OS, StringRef ClauseSetPrefix, @@ -855,6 +1081,8 @@ void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang, raw_ostream &OS) { IfDefScope Scope("GEN_DIRECTIVES_IMPL", OS); + OS << "\n#include \"llvm/Support/ErrorHandling.h\"\n"; + // getDirectiveKind(StringRef Str) GenerateGetKind(DirLang.getDirectives(), OS, "Directive", DirLang, DirLang.getDirectivePrefix(), /*ImplicitAsUnknown=*/false); @@ -877,6 +1105,12 @@ void EmitDirectivesBasicImpl(const DirectiveLanguage &DirLang, // isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) GenerateIsAllowedClause(DirLang, OS); + + // getLeafConstructs(Directive D) + GenerateGetLeafConstructs(DirLang, OS); + + // getDirectiveAssociation(Directive D) + GenerateGetDirectiveAssociation(DirLang, OS); } // Generate the implemenation section for the enumeration in the directive _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits