Skip to content

Commit 1228d42

Browse files
committed
[OpenMP][Part 2] Use reusable OpenMP context/traits handling
This patch implements an almost complete handling of OpenMP contexts/traits such that we can reuse most of the logic in Flang through the OMPContext.{h,cpp} in llvm/Frontend/OpenMP. All but construct SIMD specifiers, e.g., inbranch, and the device ISA selector are define in `llvm/lib/Frontend/OpenMP/OMPKinds.def`. From these definitions we generate the enum classes `TraitSet`, `TraitSelector`, and `TraitProperty` as well as conversion and helper functions in `llvm/lib/Frontend/OpenMP/OMPContext.{h,cpp}`. The above enum classes are used in the parser, sema, and the AST attribute. The latter is not a collection of multiple primitive variant arguments that contain encodings via numbers and strings but instead a tree that mirrors the `match` clause (see `struct OpenMPTraitInfo`). The changes to the parser make it more forgiving when wrong syntax is read and they also resulted in more specialized diagnostics. The tests are updated and the core issues are detected as before. Here and elsewhere this patch tries to be generic, thus we do not distinguish what selector set, selector, or property is parsed except if they do behave exceptionally, as for example `user={condition(EXPR)}` does. The sema logic changed in two ways: First, the OMPDeclareVariantAttr representation changed, as mentioned above, and the sema was adjusted to work with the new `OpenMPTraitInfo`. Second, the matching and scoring logic moved into `OMPContext.{h,cpp}`. It is implemented on a flat representation of the `match` clause that is not tied to clang. `OpenMPTraitInfo` provides a method to generate this flat structure (see `struct VariantMatchInfo`) by computing integer score values and boolean user conditions from the `clang::Expr` we keep for them. The OpenMP context is now an explicit object (see `struct OMPContext`). This is in anticipation of construct traits that need to be tracked. The OpenMP context, as well as the `VariantMatchInfo`, are basically made up of a set of active or respectively required traits, e.g., 'host', and an ordered container of constructs which allows duplication. Matching and scoring is kept as generic as possible to allow easy extension in the future. --- Test changes: The messages checked in `OpenMP/declare_variant_messages.{c,cpp}` have been auto generated to match the new warnings and notes of the parser. The "subset" checks were reversed causing the wrong version to be picked. The tests have been adjusted to correct this. We do not print scores if the user did not provide one. We print spaces to make lists in the `match` clause more legible. Reviewers: kiranchandramohan, ABataev, RaviNarayanaswamy, gtbercea, grokos, sdmitriev, JonChesterfield, hfinkel, fghanim Subscribers: merge_guards_bot, rampitec, mgorny, hiraditya, aheejin, fedor.sergeev, simoncook, bollu, guansong, dexonsmith, jfb, s.egerton, llvm-commits, cfe-commits Tags: #clang, #llvm Differential Revision: https://reviews.llvm.org/D71830
1 parent 4f2cccc commit 1228d42

31 files changed

+1348
-1141
lines changed

clang/include/clang/AST/Attr.h

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "clang/AST/AttrIterator.h"
1818
#include "clang/AST/Decl.h"
1919
#include "clang/AST/Expr.h"
20+
#include "clang/AST/OpenMPClause.h"
2021
#include "clang/AST/Type.h"
2122
#include "clang/Basic/AttrKinds.h"
2223
#include "clang/Basic/AttributeCommonInfo.h"

clang/include/clang/AST/OpenMPClause.h

+48
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
#include "llvm/ADT/iterator.h"
3232
#include "llvm/ADT/iterator_range.h"
3333
#include "llvm/Frontend/OpenMP/OMPConstants.h"
34+
#include "llvm/Frontend/OpenMP/OMPContext.h"
3435
#include "llvm/Support/Casting.h"
3536
#include "llvm/Support/Compiler.h"
3637
#include "llvm/Support/TrailingObjects.h"
@@ -6658,6 +6659,53 @@ class OMPClausePrinter final : public OMPClauseVisitor<OMPClausePrinter> {
66586659
#include "clang/Basic/OpenMPKinds.def"
66596660
};
66606661

6662+
/// Helper data structure representing the traits in a match clause of an
6663+
/// `declare variant` or `metadirective`. The outer level is an ordered
6664+
/// collection of selector sets, each with an associated kind and an ordered
6665+
/// collection of selectors. A selector has a kind, an optional score/condition,
6666+
/// and an ordered collection of properties.
6667+
struct OMPTraitInfo {
6668+
struct OMPTraitProperty {
6669+
llvm::omp::TraitProperty Kind = llvm::omp::TraitProperty::invalid;
6670+
};
6671+
struct OMPTraitSelector {
6672+
Expr *ScoreOrCondition = nullptr;
6673+
llvm::omp::TraitSelector Kind = llvm::omp::TraitSelector::invalid;
6674+
llvm::SmallVector<OMPTraitProperty, 4> Properties;
6675+
};
6676+
struct OMPTraitSet {
6677+
llvm::omp::TraitSet Kind = llvm::omp::TraitSet::invalid;
6678+
llvm::SmallVector<OMPTraitSelector, 4> Selectors;
6679+
};
6680+
6681+
/// The outermost level of selector sets.
6682+
llvm::SmallVector<OMPTraitSet, 4> Sets;
6683+
6684+
bool anyScoreOrCondition(
6685+
llvm::function_ref<bool(Expr *&, bool /* IsScore */)> Cond) {
6686+
return llvm::any_of(Sets, [Cond](OMPTraitInfo::OMPTraitSet &Set) {
6687+
return llvm::any_of(
6688+
Set.Selectors, [Cond](OMPTraitInfo::OMPTraitSelector &Selector) {
6689+
return Cond(Selector.ScoreOrCondition,
6690+
/* IsScore */ Selector.Kind !=
6691+
llvm::omp::TraitSelector::user_condition);
6692+
});
6693+
});
6694+
}
6695+
6696+
/// Create a variant match info object from this trait info object. While the
6697+
/// former is a flat representation the actual main difference is that the
6698+
/// latter uses clang::Expr to store the score/condition while the former is
6699+
/// independent of clang. Thus, expressions and conditions are evaluated in
6700+
/// this method.
6701+
void getAsVariantMatchInfo(ASTContext &ASTCtx,
6702+
llvm::omp::VariantMatchInfo &VMI) const;
6703+
6704+
/// Print a human readable representation into \p OS.
6705+
void print(llvm::raw_ostream &OS, const PrintingPolicy &Policy) const;
6706+
};
6707+
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const OMPTraitInfo &TI);
6708+
66616709
} // namespace clang
66626710

66636711
#endif // LLVM_CLANG_AST_OPENMPCLAUSE_H

clang/include/clang/Basic/Attr.td

+24-71
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,27 @@ class FunctionArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
180180
class NamedArgument<string name, bit opt = 0, bit fake = 0> : Argument<name,
181181
opt,
182182
fake>;
183+
184+
// An argument of a OMPDeclareVariantAttribute that represents the `match`
185+
// clause of the declare variant by keeping the information (incl. nesting) in
186+
// an OMPTraitInfo object.
187+
//
188+
// With some exceptions, the `match(<context-selector>)` clause looks roughly
189+
// as follows:
190+
// context-selector := list<selector-set>
191+
// selector-set := <kind>={list<selector>}
192+
// selector := <kind>([score(<const-expr>):] list<trait>)
193+
// trait := <kind>
194+
//
195+
// The structure of an OMPTraitInfo object is a tree as defined below:
196+
//
197+
// OMPTraitInfo := {list<OMPTraitSet>}
198+
// OMPTraitSet := {Kind, list<OMPTraitSelector>}
199+
// OMPTraitSelector := {Kind, Expr, list<OMPTraitProperty>}
200+
// OMPTraitProperty := {Kind}
201+
//
202+
class OMPTraitInfoArgument<string name> : Argument<name, 0>;
203+
183204
class TypeArgument<string name, bit opt = 0> : Argument<name, opt>;
184205
class UnsignedArgument<string name, bit opt = 0> : Argument<name, opt>;
185206
class VariadicUnsignedArgument<string name> : Argument<name, 1>;
@@ -3342,87 +3363,19 @@ def OMPDeclareVariant : InheritableAttr {
33423363
let Documentation = [OMPDeclareVariantDocs];
33433364
let Args = [
33443365
ExprArgument<"VariantFuncRef">,
3345-
VariadicExprArgument<"Scores">,
3346-
VariadicUnsignedArgument<"CtxSelectorSets">,
3347-
VariadicUnsignedArgument<"CtxSelectors">,
3348-
VariadicStringArgument<"ImplVendors">,
3349-
VariadicStringArgument<"DeviceKinds">
3366+
OMPTraitInfoArgument<"TraitInfos">,
33503367
];
33513368
let AdditionalMembers = [{
3352-
void printScore(raw_ostream & OS, const PrintingPolicy &Policy, unsigned I) const {
3353-
if (const Expr *E = *std::next(scores_begin(), I)) {
3354-
OS << "score(";
3355-
E->printPretty(OS, nullptr, Policy);
3356-
OS << "):";
3357-
}
3358-
}
3369+
~OMPDeclareVariantAttr() { delete traitInfos; }
33593370
void printPrettyPragma(raw_ostream & OS, const PrintingPolicy &Policy)
33603371
const {
33613372
if (const Expr *E = getVariantFuncRef()) {
33623373
OS << "(";
33633374
E->printPretty(OS, nullptr, Policy);
33643375
OS << ")";
33653376
}
3366-
// TODO: add printing of real context selectors.
33673377
OS << " match(";
3368-
int Used[OMP_CTX_SET_unknown] = {0};
3369-
for (unsigned I = 0, E = ctxSelectorSets_size(); I < E; ++I) {
3370-
auto CtxSet = static_cast<OpenMPContextSelectorSetKind>(
3371-
*std::next(ctxSelectorSets_begin(), I));
3372-
if (Used[CtxSet])
3373-
continue;
3374-
if (I > 0)
3375-
OS << ",";
3376-
switch (CtxSet) {
3377-
case OMP_CTX_SET_implementation:
3378-
OS << "implementation={";
3379-
break;
3380-
case OMP_CTX_SET_device:
3381-
OS << "device={";
3382-
break;
3383-
case OMP_CTX_SET_unknown:
3384-
llvm_unreachable("Unknown context selector set.");
3385-
}
3386-
Used[CtxSet] = 1;
3387-
for (unsigned K = I, EK = ctxSelectors_size(); K < EK; ++K) {
3388-
auto CtxSetK = static_cast<OpenMPContextSelectorSetKind>(
3389-
*std::next(ctxSelectorSets_begin(), K));
3390-
if (CtxSet != CtxSetK)
3391-
continue;
3392-
if (K != I)
3393-
OS << ",";
3394-
auto Ctx = static_cast<OpenMPContextSelectorKind>(
3395-
*std::next(ctxSelectors_begin(), K));
3396-
switch (Ctx) {
3397-
case OMP_CTX_vendor:
3398-
assert(CtxSet == OMP_CTX_SET_implementation &&
3399-
"Expected implementation context selector set.");
3400-
OS << "vendor(";
3401-
printScore(OS, Policy, K);
3402-
if (implVendors_size() > 0) {
3403-
OS << *implVendors(). begin();
3404-
for (StringRef VendorName : llvm::drop_begin(implVendors(), 1))
3405-
OS << ", " << VendorName;
3406-
}
3407-
OS << ")";
3408-
break;
3409-
case OMP_CTX_kind:
3410-
assert(CtxSet == OMP_CTX_SET_device &&
3411-
"Expected device context selector set.");
3412-
OS << "kind(";
3413-
if (deviceKinds_size() > 0) {
3414-
OS << *deviceKinds().begin();
3415-
for (StringRef KindName : llvm::drop_begin(deviceKinds(), 1))
3416-
OS << ", " << KindName;
3417-
}
3418-
OS << ")";
3419-
break;
3420-
case OMP_CTX_unknown:
3421-
llvm_unreachable("Unknown context selector.");
3422-
}
3423-
}
3424-
OS << "}";
3425-
}
3378+
traitInfos->print(OS, Policy);
34263379
OS << ")";
34273380
}
34283381
}];

clang/include/clang/Basic/DiagnosticParseKinds.td

+62-24
Original file line numberDiff line numberDiff line change
@@ -1258,30 +1258,68 @@ def err_omp_mapper_expected_declarator : Error<
12581258
"expected declarator on 'omp declare mapper' directive">;
12591259
def err_omp_declare_variant_wrong_clause : Error<
12601260
"expected '%0' clause on 'omp declare variant' directive">;
1261-
def err_omp_declare_variant_no_ctx_selector : Error<
1262-
"expected context selector in '%0' clause on 'omp declare variant' directive">;
1263-
def err_omp_declare_variant_equal_expected : Error<
1264-
"expected '=' after '%0' context selector set name on 'omp declare variant' directive">;
1265-
def warn_omp_declare_variant_cs_name_expected : Warning<
1266-
"unknown context selector in '%0' context selector set of 'omp declare variant' directive, ignored">,
1267-
InGroup<OpenMPClauses>;
1268-
def err_omp_declare_variant_item_expected : Error<
1269-
"expected %0 in '%1' context selector of '%2' selector set of 'omp declare variant' directive">;
1270-
def err_omp_declare_variant_ctx_set_mutiple_use : Error<
1271-
"context selector set '%0' is used already in the same 'omp declare variant' directive">;
1272-
def note_omp_declare_variant_ctx_set_used_here : Note<
1273-
"previously context selector set '%0' used here">;
1274-
def err_omp_expected_comma_brace : Error<"expected '}' or ',' after '%0'">;
1275-
def err_omp_declare_variant_ctx_mutiple_use : Error<
1276-
"context trait selector '%0' is used already in the same '%1' context selector set of 'omp declare variant' directive">;
1277-
def note_omp_declare_variant_ctx_used_here : Note<
1278-
"previously context trait selector '%0' used here">;
1279-
def warn_omp_more_one_device_type_clause : Warning<
1280-
"more than one 'device_type' clause is specified">,
1281-
InGroup<OpenMPClauses>;
1282-
def err_omp_wrong_device_kind_trait : Error<
1283-
"unknown '%0' device kind trait in the 'device' context selector set, expected"
1284-
" one of 'host', 'nohost', 'cpu', 'gpu' or 'fpga'">;
1261+
def warn_omp_declare_variant_string_literal_or_identifier
1262+
: Warning<"expected identifier or string literal describing a context "
1263+
"%select{set|selector|property}0; "
1264+
"%select{set|selector|property}0 skipped">,
1265+
InGroup<OpenMPClauses>;
1266+
def note_omp_declare_variant_ctx_options
1267+
: Note<"context %select{set|selector|property}0 options are: %1">;
1268+
def warn_omp_declare_variant_expected
1269+
: Warning<"expected '%0' after the %1; '%0' assumed">,
1270+
InGroup<OpenMPClauses>;
1271+
def warn_omp_declare_variant_ctx_not_a_property
1272+
: Warning<"'%0' is not a valid context property for the context selector "
1273+
"'%1' and the context set '%2'; property ignored">,
1274+
InGroup<OpenMPClauses>;
1275+
def note_omp_declare_variant_ctx_is_a
1276+
: Note<"'%0' is a context %select{set|selector|property}1 not a context "
1277+
"%select{set|selector|property}2">;
1278+
def note_omp_declare_variant_ctx_try : Note<"try 'match(%0={%1%2})'">;
1279+
def warn_omp_declare_variant_ctx_not_a_selector
1280+
: Warning<"'%0' is not a valid context selector for the context set '%1'; "
1281+
"selector ignored">,
1282+
InGroup<OpenMPClauses>;
1283+
def warn_omp_declare_variant_ctx_not_a_set
1284+
: Warning<"'%0' is not a valid context set in a `declare variant`; set "
1285+
"ignored">,
1286+
InGroup<OpenMPClauses>;
1287+
def warn_omp_declare_variant_ctx_mutiple_use
1288+
: Warning<"the context %select{set|selector|property}0 '%1' was used "
1289+
"already in the same 'omp declare variant' directive; "
1290+
"%select{set|selector|property}0 ignored">,
1291+
InGroup<OpenMPClauses>;
1292+
def note_omp_declare_variant_ctx_used_here
1293+
: Note<"the previous context %select{set|selector|property}0 '%1' used "
1294+
"here">;
1295+
def note_omp_declare_variant_ctx_continue_here
1296+
: Note<"the ignored %select{set|selector|property}0 spans until here">;
1297+
def warn_omp_ctx_incompatible_selector_for_set
1298+
: Warning<"the context selector '%0' is not valid for the context set "
1299+
"'%1'; selector ignored">,
1300+
InGroup<OpenMPClauses>;
1301+
def note_omp_ctx_compatible_set_for_selector
1302+
: Note<"the context selector '%0' can be nested in the context set '%1'; "
1303+
"try 'match(%1={%0%select{|(property)}2})'">;
1304+
def warn_omp_ctx_selector_without_properties
1305+
: Warning<"the context selector '%0' in context set '%1' requires a "
1306+
"context property defined in parentheses; selector ignored">,
1307+
InGroup<OpenMPClauses>;
1308+
def warn_omp_ctx_incompatible_property_for_selector
1309+
: Warning<"the context property '%0' is not valid for the context selector "
1310+
"'%1' and the context set '%2'; property ignored">,
1311+
InGroup<OpenMPClauses>;
1312+
def note_omp_ctx_compatible_set_and_selector_for_property
1313+
: Note<"the context property '%0' can be nested in the context selector "
1314+
"'%1' which is nested in the context set '%2'; try "
1315+
"'match(%2={%1(%0)})'">;
1316+
def warn_omp_ctx_incompatible_score_for_property
1317+
: Warning<"the context selector '%0' in the context set '%1' cannot have a "
1318+
"score ('%2'); score ignored">,
1319+
InGroup<OpenMPClauses>;
1320+
def warn_omp_more_one_device_type_clause
1321+
: Warning<"more than one 'device_type' clause is specified">,
1322+
InGroup<OpenMPClauses>;
12851323

12861324
// Pragma loop support.
12871325
def err_pragma_loop_missing_argument : Error<

clang/include/clang/Basic/DiagnosticSemaKinds.td

+6
Original file line numberDiff line numberDiff line change
@@ -9910,6 +9910,12 @@ def warn_omp_declare_target_after_first_use : Warning<
99109910
InGroup<OpenMPTarget>;
99119911
def err_omp_declare_variant_incompat_attributes : Error<
99129912
"'#pragma omp declare variant' is not compatible with any target-specific attributes">;
9913+
def warn_omp_declare_variant_score_not_constant
9914+
: Warning<"score expressions in the OpenMP context selector need to be "
9915+
"constant; %0 is not and will be ignored">;
9916+
def err_omp_declare_variant_user_condition_not_constant
9917+
: Error<"the user condition in the OpenMP context selector needs to be "
9918+
"constant; %0 is not">;
99139919
def warn_omp_declare_variant_after_used : Warning<
99149920
"'#pragma omp declare variant' cannot be applied for function after first "
99159921
"usage; the original function might be used">, InGroup<SourceUsesOpenMP>;

clang/include/clang/Basic/OpenMPKinds.def

-16
Original file line numberDiff line numberDiff line change
@@ -203,12 +203,6 @@
203203
#ifndef OPENMP_DECLARE_VARIANT_CLAUSE
204204
#define OPENMP_DECLARE_VARIANT_CLAUSE(Name)
205205
#endif
206-
#ifndef OPENMP_CONTEXT_SELECTOR_SET
207-
#define OPENMP_CONTEXT_SELECTOR_SET(Name)
208-
#endif
209-
#ifndef OPENMP_CONTEXT_SELECTOR
210-
#define OPENMP_CONTEXT_SELECTOR(Name)
211-
#endif
212206
#ifndef OPENMP_LASTPRIVATE_KIND
213207
#define OPENMP_LASTPRIVATE_KIND(Name)
214208
#endif
@@ -219,14 +213,6 @@
219213
#define OPENMP_FLUSH_CLAUSE(Name)
220214
#endif
221215

222-
// OpenMP context selector sets.
223-
OPENMP_CONTEXT_SELECTOR_SET(implementation)
224-
OPENMP_CONTEXT_SELECTOR_SET(device)
225-
226-
// OpenMP context selectors.
227-
OPENMP_CONTEXT_SELECTOR(vendor)
228-
OPENMP_CONTEXT_SELECTOR(kind)
229-
230216
// OpenMP clauses.
231217
OPENMP_CLAUSE(allocator, OMPAllocatorClause)
232218
OPENMP_CLAUSE(if, OMPIfClause)
@@ -1102,8 +1088,6 @@ OPENMP_FLUSH_CLAUSE(release)
11021088
#undef OPENMP_FLUSH_CLAUSE
11031089
#undef OPENMP_ORDER_KIND
11041090
#undef OPENMP_LASTPRIVATE_KIND
1105-
#undef OPENMP_CONTEXT_SELECTOR
1106-
#undef OPENMP_CONTEXT_SELECTOR_SET
11071091
#undef OPENMP_DECLARE_VARIANT_CLAUSE
11081092
#undef OPENMP_DEVICE_TYPE_KIND
11091093
#undef OPENMP_ALLOCATE_CLAUSE

clang/include/clang/Basic/OpenMPKinds.h

-39
Original file line numberDiff line numberDiff line change
@@ -19,45 +19,6 @@
1919

2020
namespace clang {
2121

22-
/// OpenMP context selector sets.
23-
enum OpenMPContextSelectorSetKind {
24-
#define OPENMP_CONTEXT_SELECTOR_SET(Name) OMP_CTX_SET_##Name,
25-
#include "clang/Basic/OpenMPKinds.def"
26-
OMP_CTX_SET_unknown,
27-
};
28-
29-
/// OpenMP context selectors.
30-
enum OpenMPContextSelectorKind {
31-
#define OPENMP_CONTEXT_SELECTOR(Name) OMP_CTX_##Name,
32-
#include "clang/Basic/OpenMPKinds.def"
33-
OMP_CTX_unknown,
34-
};
35-
36-
OpenMPContextSelectorSetKind getOpenMPContextSelectorSet(llvm::StringRef Str);
37-
llvm::StringRef
38-
getOpenMPContextSelectorSetName(OpenMPContextSelectorSetKind Kind);
39-
OpenMPContextSelectorKind getOpenMPContextSelector(llvm::StringRef Str);
40-
llvm::StringRef getOpenMPContextSelectorName(OpenMPContextSelectorKind Kind);
41-
42-
/// Struct to store the context selectors info.
43-
template <typename VectorType, typename ScoreT> struct OpenMPCtxSelectorData {
44-
OpenMPContextSelectorSetKind CtxSet = OMP_CTX_SET_unknown;
45-
OpenMPContextSelectorKind Ctx = OMP_CTX_unknown;
46-
ScoreT Score;
47-
VectorType Names;
48-
explicit OpenMPCtxSelectorData() = default;
49-
explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet,
50-
OpenMPContextSelectorKind Ctx,
51-
const ScoreT &Score, VectorType &&Names)
52-
: CtxSet(CtxSet), Ctx(Ctx), Score(Score), Names(Names) {}
53-
template <typename U>
54-
explicit OpenMPCtxSelectorData(OpenMPContextSelectorSetKind CtxSet,
55-
OpenMPContextSelectorKind Ctx,
56-
const ScoreT &Score, const U &Names)
57-
: CtxSet(CtxSet), Ctx(Ctx), Score(Score),
58-
Names(Names.begin(), Names.end()) {}
59-
};
60-
6122
/// OpenMP directives.
6223
using OpenMPDirectiveKind = llvm::omp::Directive;
6324

0 commit comments

Comments
 (0)