1//===-- OMPDescriptors.cpp - OpenMP descriptors ------------------- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains descriptors of OpenMP elements.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/Frontend/OpenMP/OMPDescriptors.h"
14
15#include <map>
16
17// For unassociated directives the .inc file uses an "Unassociated" enum
18// (since it's the name used in the OpenMP spec), while the existing enum
19// (in OMP.h.inc) uses "None". Redefine the token "Unassociated" to "None"
20// in this file to allow the reuse of the pre-existing enum.
21#define Unassociated None
22
23namespace llvm::omp {
24const DescriptorMap<Clause, descriptor::Clause> &getClauseMap() {
25 static const DescriptorMap<Clause, descriptor::Clause> Map{
26#define GEN_OMP_CLAUSE_DESCRIPTORS
27#include "OMPDescriptors.inc"
28#undef GEN_OMP_CLAUSE_DESCRIPTORS
29 };
30 return Map;
31}
32
33const DescriptorMap<ClauseSet, descriptor::ClauseSet> &getClauseSetMap() {
34 static const DescriptorMap<ClauseSet, descriptor::ClauseSet> Map{
35#define GEN_OMP_CLAUSE_GROUP_DESCRIPTORS
36#include "OMPDescriptors.inc"
37#undef GEN_OMP_CLAUSE_GROUP_DESCRIPTORS
38
39#define GEN_OMP_CLAUSE_SET_DESCRIPTORS
40#include "OMPDescriptors.inc"
41#undef GEN_OMP_CLAUSE_SET_DESCRIPTORS
42 };
43 return Map;
44}
45
46const DescriptorMap<Directive, descriptor::Directive> &getDirectiveMap() {
47 static const DescriptorMap<Directive, descriptor::Directive> Map{
48#define GEN_OMP_DIRECTIVE_DESCRIPTORS
49#include "OMPDescriptors.inc"
50#undef GEN_OMP_DIRECTIVE_DESCRIPTORS
51 };
52 return Map;
53}
54
55const DescriptorMap<Modifier, descriptor::Modifier> &getModifierMap() {
56 static const DescriptorMap<Modifier, descriptor::Modifier> Map{
57#define GEN_OMP_MODIFIER_DESCRIPTORS
58#include "OMPDescriptors.inc"
59#undef GEN_OMP_MODIFIER_DESCRIPTORS
60 };
61 return Map;
62}
63
64const DescriptorMap<ModifierSet, descriptor::ModifierSet> &getModifierSetMap() {
65 static const DescriptorMap<ModifierSet, descriptor::ModifierSet> Map{
66#define GEN_OMP_MODIFIER_GROUP_DESCRIPTORS
67#include "OMPDescriptors.inc"
68#undef GEN_OMP_MODIFIER_GROUP_DESCRIPTORS
69
70#define GEN_OMP_MODIFIER_SET_DESCRIPTORS
71#include "OMPDescriptors.inc"
72#undef GEN_OMP_MODIFIER_SET_DESCRIPTORS
73 };
74 return Map;
75}
76
77#define GET_THING_OR_EMPTY(Thing, Member) \
78 template <typename DetailsTy> \
79 static Thing get##Thing##OrEmpty(const DetailsTy &D, Version V) { \
80 V = std::max(V, Version(45)); \
81 if (auto Found = D.find(V); Found != D.end()) \
82 return Found->second.Member; \
83 return Thing{}; \
84 }
85
86GET_THING_OR_EMPTY(Clauses, Cls)
87GET_THING_OR_EMPTY(ClauseSets, ClsSets)
88GET_THING_OR_EMPTY(Directives, Dirs)
89GET_THING_OR_EMPTY(Modifiers, Mods)
90GET_THING_OR_EMPTY(ModifierSets, ModSets)
91GET_THING_OR_EMPTY(Properties, Props)
92
93#undef GET_THING_OR_EMPTY
94
95// Clause
96Properties descriptor::Clause::getProperties(Version V) const {
97 return getPropertiesOrEmpty(D: Details, V);
98}
99Directives descriptor::Clause::getDirectives(Version V) const {
100 return getDirectivesOrEmpty(D: Details, V);
101}
102Modifiers descriptor::Clause::getModifiers(Version V) const {
103 return getModifiersOrEmpty(D: Details, V);
104}
105ModifierSets descriptor::Clause::getModifierSets(Version V) const {
106 return getModifierSetsOrEmpty(D: Details, V);
107}
108// ClauseSet
109Properties descriptor::ClauseSet::getProperties(Version V) const {
110 return getPropertiesOrEmpty(D: Details, V);
111}
112Clauses descriptor::ClauseSet::getClauses(Version V) const {
113 return getClausesOrEmpty(D: Details, V);
114}
115Directives descriptor::ClauseSet::getDirectives(Version V) const {
116 return getDirectivesOrEmpty(D: Details, V);
117}
118// Directive
119Properties descriptor::Directive::getProperties(Version V) const {
120 return getPropertiesOrEmpty(D: Details, V);
121}
122Association descriptor::Directive::getAssociation(Version V) const {
123 return Details.at(Val: std::max(a: V, b: Version(45))).Assoc;
124}
125Category descriptor::Directive::getCategory(Version V) const {
126 return Details.at(Val: std::max(a: V, b: Version(45))).Cat;
127}
128Clauses descriptor::Directive::getClauses(Version V) const {
129 return getClausesOrEmpty(D: Details, V);
130}
131ClauseSets descriptor::Directive::getClauseSets(Version V) const {
132 return getClauseSetsOrEmpty(D: Details, V);
133}
134
135// Modifier
136Properties descriptor::Modifier::getProperties(Version V) const {
137 return getPropertiesOrEmpty(D: Details, V);
138}
139Clauses descriptor::Modifier::getClauses(Version V) const {
140 return getClausesOrEmpty(D: Details, V);
141}
142// ModifierSet
143Properties descriptor::ModifierSet::getProperties(Version V) const {
144 return getPropertiesOrEmpty(D: Details, V);
145}
146Modifiers descriptor::ModifierSet::getModifiers(Version V) const {
147 return getModifiersOrEmpty(D: Details, V);
148}
149Clauses descriptor::ModifierSet::getClauses(Version V) const {
150 return getClausesOrEmpty(D: Details, V);
151}
152
153const descriptor::Clause &getDescriptor(Clause C) {
154 return getClauseMap().at(Val: C);
155}
156
157const descriptor::ClauseSet &getDescriptor(ClauseSet S) {
158 return getClauseSetMap().at(Val: S);
159}
160
161const descriptor::Directive &getDescriptor(Directive D) {
162 ArrayRef<llvm::omp::Directive> Leafs = llvm::omp::getLeafConstructsOrSelf(D);
163 if (Leafs.size() == 1)
164 return getDirectiveMap().at(Val: Leafs[0]);
165
166 static std::map<Directive, descriptor::Directive> Compound;
167 if (auto F = Compound.find(x: D); F != Compound.end())
168 return F->second;
169
170 // Combine details from all leafs into a single map and create a descriptor
171 // from it.
172 using Details = descriptor::details::Directive;
173 using DetailsMap = descriptor::DetailsMap<Details>;
174 DetailsMap Det;
175 // The name of the descriptor will be the spelling from the latest supported
176 // version.
177 llvm::omp::Version MaxV(0);
178
179 for (llvm::omp::Directive L : Leafs) {
180 const auto &Desc{getDescriptor(D: L)};
181 for (auto &[V, T] : Desc.getDetails()) {
182 MaxV = std::max(a: MaxV, b: V); // Used for descriptor's name.
183 auto F = Det.insert(KV: {V, Details{}}).first;
184 // Compound directives do not have properties. Their semantics or
185 // restrictions need to be inferred from the properties of their
186 // constituents.
187 F->second.Spelling = getOpenMPDirectiveName(D, V);
188 // The category should be the same for all of them (i.e. executable),
189 // the association of the last one is the association of the whole
190 // directive. Since the leafs are ordered from the outermost to the
191 // innermost it is safe to simply overwrite the non-set members each
192 // time.
193 F->second.Assoc = T.Assoc;
194 F->second.Cat = T.Cat;
195 F->second.Cls |= T.Cls;
196 F->second.ClsSets |= T.ClsSets;
197 }
198 }
199
200 auto At =
201 Compound.try_emplace(k: D, args: getOpenMPDirectiveName(D, V: MaxV), args: std::move(Det));
202 return At.first->second;
203}
204
205const descriptor::Modifier &getDescriptor(Modifier M) {
206 return getModifierMap().at(Val: M);
207}
208
209const descriptor::ModifierSet &getDescriptor(ModifierSet S) {
210 return getModifierSetMap().at(Val: S);
211}
212
213Properties getProperties(Clause C, Version V) {
214 return getDescriptor(C).getProperties(V: std::max(a: V, b: Version(45)));
215}
216} // namespace llvm::omp
217
218#undef Unassociated
219