Skip to content

Commit e6c5e6e

Browse files
[MLIR,OpenMP] Lowering of parallel operation: proc_bind clause 2/n
This patch adds the translation of the proc_bind clause in a parallel operation. The values that can be specified for the proc_bind clause are specified in the OMP.td tablegen file in the llvm/Frontend/OpenMP directory. From this single source of truth enumeration for proc_bind is generated in llvm and mlir (used in specification of the parallel Operation in the OpenMP dialect). A function to return the enum value from the string representation is also generated. A new header file (DirectiveEmitter.h) containing definitions of classes directive, clause, clauseval etc is created so that it can be used in mlir as well. Reviewers: clementval, jdoerfert, DavidTruby Differential Revision: https://reviews.llvm.org/D84347
1 parent 6b3dc96 commit e6c5e6e

File tree

12 files changed

+490
-215
lines changed

12 files changed

+490
-215
lines changed

llvm/include/llvm/Frontend/Directive/DirectiveBase.td

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,21 @@ class DirectiveLanguage {
5151
string flangClauseBaseClass = "";
5252
}
5353

54+
// Information about values accepted by enum-like clauses
55+
class ClauseVal<string n, int v, bit uv> {
56+
// Name of the clause value.
57+
string name = n;
58+
59+
// Integer value of the clause.
60+
int value = v;
61+
62+
// Can user specify this value?
63+
bit isUserValue = uv;
64+
65+
// Set clause value used by default when unknown.
66+
bit isDefault = 0;
67+
}
68+
5469
// Information about a specific clause.
5570
class Clause<string c> {
5671
// Name of the clause.
@@ -75,11 +90,17 @@ class Clause<string c> {
7590
// If set to 1, value is optional. Not optional by default.
7691
bit isValueOptional = 0;
7792

93+
// Name of enum when there is a list of allowed clause values.
94+
string enumClauseValue = "";
95+
96+
// List of allowed clause values
97+
list<ClauseVal> allowedClauseValues = [];
98+
7899
// Is clause implicit? If clause is set as implicit, the default kind will
79100
// be return in get<LanguageName>ClauseKind instead of their own kind.
80101
bit isImplicit = 0;
81102

82-
// Set directive used by default when unknown. Function returning the kind
103+
// Set clause used by default when unknown. Function returning the kind
83104
// of enumeration will use this clause as the default.
84105
bit isDefault = 0;
85106
}

llvm/include/llvm/Frontend/OpenMP/OMP.td

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,22 @@ def OMPC_CopyPrivate : Clause<"copyprivate"> {
9999
let clangClass = "OMPCopyprivateClause";
100100
let flangClassValue = "OmpObjectList";
101101
}
102+
def OMP_PROC_BIND_master : ClauseVal<"master",2,1> {}
103+
def OMP_PROC_BIND_close : ClauseVal<"close",3,1> {}
104+
def OMP_PROC_BIND_spread : ClauseVal<"spread",4,1> {}
105+
def OMP_PROC_BIND_default : ClauseVal<"default",5,0> {}
106+
def OMP_PROC_BIND_unknown : ClauseVal<"unknown",6,0> { let isDefault = 1; }
102107
def OMPC_ProcBind : Clause<"proc_bind"> {
103108
let clangClass = "OMPProcBindClause";
104109
let flangClass = "OmpProcBindClause";
110+
let enumClauseValue = "ProcBindKind";
111+
let allowedClauseValues = [
112+
OMP_PROC_BIND_master,
113+
OMP_PROC_BIND_close,
114+
OMP_PROC_BIND_spread,
115+
OMP_PROC_BIND_default,
116+
OMP_PROC_BIND_unknown
117+
];
105118
}
106119
def OMPC_Schedule : Clause<"schedule"> {
107120
let clangClass = "OMPScheduleClause";

llvm/include/llvm/Frontend/OpenMP/OMPConstants.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -68,16 +68,6 @@ enum class DefaultKind {
6868
constexpr auto Enum = omp::DefaultKind::Enum;
6969
#include "llvm/Frontend/OpenMP/OMPKinds.def"
7070

71-
/// IDs for the different proc bind kinds.
72-
enum class ProcBindKind {
73-
#define OMP_PROC_BIND_KIND(Enum, Str, Value) Enum = Value,
74-
#include "llvm/Frontend/OpenMP/OMPKinds.def"
75-
};
76-
77-
#define OMP_PROC_BIND_KIND(Enum, ...) \
78-
constexpr auto Enum = omp::ProcBindKind::Enum;
79-
#include "llvm/Frontend/OpenMP/OMPKinds.def"
80-
8171
/// IDs for all omp runtime library ident_t flag encodings (see
8272
/// their defintion in openmp/runtime/src/kmp.h).
8373
enum class IdentFlag {
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
#ifndef LLVM_TABLEGEN_DIRECTIVEEMITTER_H
2+
#define LLVM_TABLEGEN_DIRECTIVEEMITTER_H
3+
4+
#include "llvm/ADT/StringExtras.h"
5+
#include "llvm/TableGen/Record.h"
6+
7+
namespace llvm {
8+
9+
// Wrapper class that contains DirectiveLanguage's information defined in
10+
// DirectiveBase.td and provides helper methods for accessing it.
11+
class DirectiveLanguage {
12+
public:
13+
explicit DirectiveLanguage(const llvm::Record *Def) : Def(Def) {}
14+
15+
StringRef getName() const { return Def->getValueAsString("name"); }
16+
17+
StringRef getCppNamespace() const {
18+
return Def->getValueAsString("cppNamespace");
19+
}
20+
21+
StringRef getDirectivePrefix() const {
22+
return Def->getValueAsString("directivePrefix");
23+
}
24+
25+
StringRef getClausePrefix() const {
26+
return Def->getValueAsString("clausePrefix");
27+
}
28+
29+
StringRef getIncludeHeader() const {
30+
return Def->getValueAsString("includeHeader");
31+
}
32+
33+
StringRef getClauseEnumSetClass() const {
34+
return Def->getValueAsString("clauseEnumSetClass");
35+
}
36+
37+
StringRef getFlangClauseBaseClass() const {
38+
return Def->getValueAsString("flangClauseBaseClass");
39+
}
40+
41+
bool hasMakeEnumAvailableInNamespace() const {
42+
return Def->getValueAsBit("makeEnumAvailableInNamespace");
43+
}
44+
45+
bool hasEnableBitmaskEnumInNamespace() const {
46+
return Def->getValueAsBit("enableBitmaskEnumInNamespace");
47+
}
48+
49+
private:
50+
const llvm::Record *Def;
51+
};
52+
53+
// Base record class used for Directive and Clause class defined in
54+
// DirectiveBase.td.
55+
class BaseRecord {
56+
public:
57+
explicit BaseRecord(const llvm::Record *Def) : Def(Def) {}
58+
59+
StringRef getName() const { return Def->getValueAsString("name"); }
60+
61+
StringRef getAlternativeName() const {
62+
return Def->getValueAsString("alternativeName");
63+
}
64+
65+
// Returns the name of the directive formatted for output. Whitespace are
66+
// replaced with underscores.
67+
std::string getFormattedName() {
68+
StringRef Name = Def->getValueAsString("name");
69+
std::string N = Name.str();
70+
std::replace(N.begin(), N.end(), ' ', '_');
71+
return N;
72+
}
73+
74+
bool isDefault() const { return Def->getValueAsBit("isDefault"); }
75+
76+
protected:
77+
const llvm::Record *Def;
78+
};
79+
80+
// Wrapper class that contains a Directive's information defined in
81+
// DirectiveBase.td and provides helper methods for accessing it.
82+
class Directive : public BaseRecord {
83+
public:
84+
explicit Directive(const llvm::Record *Def) : BaseRecord(Def) {}
85+
86+
std::vector<Record *> getAllowedClauses() const {
87+
return Def->getValueAsListOfDefs("allowedClauses");
88+
}
89+
90+
std::vector<Record *> getAllowedOnceClauses() const {
91+
return Def->getValueAsListOfDefs("allowedOnceClauses");
92+
}
93+
94+
std::vector<Record *> getAllowedExclusiveClauses() const {
95+
return Def->getValueAsListOfDefs("allowedExclusiveClauses");
96+
}
97+
98+
std::vector<Record *> getRequiredClauses() const {
99+
return Def->getValueAsListOfDefs("requiredClauses");
100+
}
101+
};
102+
103+
// Wrapper class that contains Clause's information defined in DirectiveBase.td
104+
// and provides helper methods for accessing it.
105+
class Clause : public BaseRecord {
106+
public:
107+
explicit Clause(const llvm::Record *Def) : BaseRecord(Def) {}
108+
109+
// Optional field.
110+
StringRef getClangClass() const {
111+
return Def->getValueAsString("clangClass");
112+
}
113+
114+
// Optional field.
115+
StringRef getFlangClass() const {
116+
return Def->getValueAsString("flangClass");
117+
}
118+
119+
// Optional field.
120+
StringRef getFlangClassValue() const {
121+
return Def->getValueAsString("flangClassValue");
122+
}
123+
124+
// Get the formatted name for Flang parser class. The generic formatted class
125+
// name is constructed from the name were the first letter of each word is
126+
// captitalized and the underscores are removed.
127+
// ex: async -> Async
128+
// num_threads -> NumThreads
129+
std::string getFormattedParserClassName() {
130+
StringRef Name = Def->getValueAsString("name");
131+
std::string N = Name.str();
132+
bool Cap = true;
133+
std::transform(N.begin(), N.end(), N.begin(), [&Cap](unsigned char C) {
134+
if (Cap == true) {
135+
C = llvm::toUpper(C);
136+
Cap = false;
137+
} else if (C == '_') {
138+
Cap = true;
139+
}
140+
return C;
141+
});
142+
N.erase(std::remove(N.begin(), N.end(), '_'), N.end());
143+
return N;
144+
}
145+
146+
// Optional field.
147+
StringRef getEnumName() const {
148+
return Def->getValueAsString("enumClauseValue");
149+
}
150+
151+
std::vector<Record *> getClauseVals() const {
152+
return Def->getValueAsListOfDefs("allowedClauseValues");
153+
}
154+
155+
bool isValueOptional() const { return Def->getValueAsBit("isValueOptional"); }
156+
157+
bool isImplict() const { return Def->getValueAsBit("isImplicit"); }
158+
};
159+
160+
// Wrapper class that contains VersionedClause's information defined in
161+
// DirectiveBase.td and provides helper methods for accessing it.
162+
class VersionedClause {
163+
public:
164+
explicit VersionedClause(const llvm::Record *Def) : Def(Def) {}
165+
166+
// Return the specific clause record wrapped in the Clause class.
167+
Clause getClause() const { return Clause{Def->getValueAsDef("clause")}; }
168+
169+
int64_t getMinVersion() const { return Def->getValueAsInt("minVersion"); }
170+
171+
int64_t getMaxVersion() const { return Def->getValueAsInt("maxVersion"); }
172+
173+
private:
174+
const llvm::Record *Def;
175+
};
176+
177+
class ClauseVal : public BaseRecord {
178+
public:
179+
explicit ClauseVal(const llvm::Record *Def) : BaseRecord(Def) {}
180+
181+
int getValue() const { return Def->getValueAsInt("value"); }
182+
183+
bool isUserVisible() const { return Def->getValueAsBit("isUserValue"); }
184+
};
185+
186+
} // namespace llvm
187+
188+
#endif

llvm/test/TableGen/directive1.td

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,20 @@ def TestDirectiveLanguage : DirectiveLanguage {
1515
let flangClauseBaseClass = "TdlClause";
1616
}
1717

18+
def TDLCV_vala : ClauseVal<"vala",1,1> {}
19+
def TDLCV_valb : ClauseVal<"valb",2,1> {}
20+
def TDLCV_valc : ClauseVal<"valc",3,0> { let isDefault = 1; }
21+
1822
def TDLC_ClauseA : Clause<"clausea"> {
1923
let flangClass = "TdlClauseA";
24+
let enumClauseValue = "AKind";
25+
let allowedClauseValues = [
26+
TDLCV_vala,
27+
TDLCV_valb,
28+
TDLCV_valc
29+
];
2030
}
31+
2132
def TDLC_ClauseB : Clause<"clauseb"> {
2233
let flangClassValue = "IntExpr";
2334
let isValueOptional = 1;
@@ -61,6 +72,16 @@ def TDL_DirA : Directive<"dira"> {
6172
// CHECK-NEXT: constexpr auto TDLC_clausea = llvm::tdl::Clause::TDLC_clausea;
6273
// CHECK-NEXT: constexpr auto TDLC_clauseb = llvm::tdl::Clause::TDLC_clauseb;
6374
// CHECK-EMPTY:
75+
// CHECK-NEXT: enum class AKind {
76+
// CHECK-NEXT: TDLCV_vala=1,
77+
// CHECK-NEXT: TDLCV_valb=2,
78+
// CHECK-NEXT: TDLCV_valc=3,
79+
// CHECK-NEXT: };
80+
// CHECK-EMPTY:
81+
// CHECK-NEXT: constexpr auto TDLCV_vala = llvm::tdl::AKind::TDLCV_vala;
82+
// CHECK-NEXT: constexpr auto TDLCV_valb = llvm::tdl::AKind::TDLCV_valb;
83+
// CHECK-NEXT: constexpr auto TDLCV_valc = llvm::tdl::AKind::TDLCV_valc;
84+
// CHECK-EMPTY:
6485
// CHECK-NEXT: // Enumeration helper functions
6586
// CHECK-NEXT: Directive getTdlDirectiveKind(llvm::StringRef Str);
6687
// CHECK-EMPTY:
@@ -73,6 +94,8 @@ def TDL_DirA : Directive<"dira"> {
7394
// CHECK-NEXT: /// Return true if \p C is a valid clause for \p D in version \p Version.
7495
// CHECK-NEXT: bool isAllowedClauseForDirective(Directive D, Clause C, unsigned Version);
7596
// CHECK-EMPTY:
97+
// CHECK-NEXT: AKind getAKind(StringRef);
98+
// CHECK-EMPTY:
7699
// CHECK-NEXT: } // namespace tdl
77100
// CHECK-NEXT: } // namespace llvm
78101
// CHECK-NEXT: #endif // LLVM_Tdl_INC
@@ -116,6 +139,14 @@ def TDL_DirA : Directive<"dira"> {
116139
// IMPL-NEXT: llvm_unreachable("Invalid Tdl Clause kind");
117140
// IMPL-NEXT: }
118141
// IMPL-EMPTY:
142+
// IMPL-NEXT: AKind llvm::tdl::getAKind(llvm::StringRef Str) {
143+
// IMPL-NEXT: return llvm::StringSwitch<AKind>(Str)
144+
// IMPL-NEXT: .Case("vala",TDLCV_vala)
145+
// IMPL-NEXT: .Case("valb",TDLCV_valb)
146+
// IMPL-NEXT: .Case("valc",TDLCV_valc)
147+
// IMPL-NEXT: .Default(TDLCV_valc);
148+
// IMPL-NEXT: }
149+
// IMPL-EMPTY:
119150
// IMPL-NEXT: bool llvm::tdl::isAllowedClauseForDirective(Directive D, Clause C, unsigned Version) {
120151
// IMPL-NEXT: assert(unsigned(D) <= llvm::tdl::Directive_enumSize);
121152
// IMPL-NEXT: assert(unsigned(C) <= llvm::tdl::Clause_enumSize);

0 commit comments

Comments
 (0)