Skip to content

Commit cb564f1

Browse files
committed
OpenMP stylized expressions
1 parent 26db214 commit cb564f1

File tree

11 files changed

+336
-91
lines changed

11 files changed

+336
-91
lines changed

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -674,6 +674,10 @@ class ParseTreeDumper {
674674
NODE_ENUM(OmpSeverityClause, Severity)
675675
NODE(parser, OmpStepComplexModifier)
676676
NODE(parser, OmpStepSimpleModifier)
677+
NODE(parser, OmpStylizedDeclaration)
678+
NODE(parser, OmpStylizedExpression)
679+
NODE(parser, OmpStylizedInstance)
680+
NODE(OmpStylizedInstance, Instance)
677681
NODE(parser, OmpTaskDependenceType)
678682
NODE_ENUM(OmpTaskDependenceType, Value)
679683
NODE(parser, OmpTaskReductionClause)

flang/include/flang/Parser/openmp-utils.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,13 @@
2525

2626
namespace Fortran::parser::omp {
2727

28+
template <typename T> constexpr auto addr_if(std::optional<T> &x) {
29+
return x ? &*x : nullptr;
30+
}
31+
template <typename T> constexpr auto addr_if(const std::optional<T> &x) {
32+
return x ? &*x : nullptr;
33+
}
34+
2835
namespace detail {
2936
using D = llvm::omp::Directive;
3037

@@ -133,9 +140,24 @@ template <typename T> OmpDirectiveName GetOmpDirectiveName(const T &x) {
133140
}
134141

135142
const OmpObjectList *GetOmpObjectList(const OmpClause &clause);
143+
144+
template <typename T>
145+
const T *GetFirstArgument(const OmpDirectiveSpecification &spec) {
146+
for (const OmpArgument &arg : spec.Arguments().v) {
147+
if (auto *t{std::get_if<T>(&arg.u)}) {
148+
return t;
149+
}
150+
}
151+
return nullptr;
152+
}
153+
136154
const BlockConstruct *GetFortranBlockConstruct(
137155
const ExecutionPartConstruct &epc);
138156

157+
const OmpCombinerExpression *GetCombinerExpr(
158+
const OmpReductionSpecifier &rspec);
159+
const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init);
160+
139161
} // namespace Fortran::parser::omp
140162

141163
#endif // FORTRAN_PARSER_OPENMP_UTILS_H

flang/include/flang/Parser/parse-tree.h

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,9 @@
2424
#include "provenance.h"
2525
#include "flang/Common/idioms.h"
2626
#include "flang/Common/indirection.h"
27+
#include "flang/Common/reference.h"
2728
#include "flang/Support/Fortran.h"
29+
#include "llvm/ADT/ArrayRef.h"
2830
#include "llvm/Frontend/OpenACC/ACC.h.inc"
2931
#include "llvm/Frontend/OpenMP/OMP.h"
3032
#include "llvm/Frontend/OpenMP/OMPConstants.h"
@@ -3504,6 +3506,8 @@ struct OmpDirectiveName {
35043506

35053507
// type-name list item
35063508
struct OmpTypeName {
3509+
CharBlock source;
3510+
mutable const semantics::DeclTypeSpec *declTypeSpec{nullptr};
35073511
UNION_CLASS_BOILERPLATE(OmpTypeName);
35083512
std::variant<TypeSpec, DeclarationTypeSpec> u;
35093513
};
@@ -3532,6 +3536,32 @@ struct OmpObjectList {
35323536
WRAPPER_CLASS_BOILERPLATE(OmpObjectList, std::list<OmpObject>);
35333537
};
35343538

3539+
struct OmpStylizedDeclaration {
3540+
COPY_AND_ASSIGN_BOILERPLATE(OmpStylizedDeclaration);
3541+
using EmptyTrait = std::true_type;
3542+
common::Reference<const OmpTypeName> type;
3543+
EntityDecl var;
3544+
};
3545+
3546+
struct OmpStylizedInstance {
3547+
struct Instance {
3548+
UNION_CLASS_BOILERPLATE(Instance);
3549+
std::variant<AssignmentStmt, CallStmt, common::Indirection<Expr>>
3550+
u;
3551+
};
3552+
TUPLE_CLASS_BOILERPLATE(OmpStylizedInstance);
3553+
std::tuple<std::list<OmpStylizedDeclaration>, Instance> t;
3554+
};
3555+
3556+
class ParseState;
3557+
3558+
struct OmpStylizedExpression {
3559+
CharBlock source;
3560+
const ParseState *state{nullptr};
3561+
WRAPPER_CLASS_BOILERPLATE(
3562+
OmpStylizedExpression, std::list<OmpStylizedInstance>);
3563+
};
3564+
35353565
// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
35363566
//
35373567
// reduction-identifier ->
@@ -3549,9 +3579,22 @@ struct OmpReductionIdentifier {
35493579
// combiner-expression -> // since 4.5
35503580
// assignment-statement |
35513581
// function-reference
3552-
struct OmpCombinerExpression {
3553-
UNION_CLASS_BOILERPLATE(OmpCombinerExpression);
3554-
std::variant<AssignmentStmt, FunctionReference> u;
3582+
struct OmpCombinerExpression : public OmpStylizedExpression {
3583+
INHERITED_WRAPPER_CLASS_BOILERPLATE(
3584+
OmpCombinerExpression, OmpStylizedExpression);
3585+
static llvm::ArrayRef<CharBlock> Variables();
3586+
};
3587+
3588+
// Ref: [4.5:222:7-8], [5.0:305:28-29], [5.1:337:20-21], [5.2:127:6-8],
3589+
// [6.0:242:3-5]
3590+
//
3591+
// initializer-expression -> // since 4.5
3592+
// OMP_PRIV = expression |
3593+
// subroutine-name(argument-list)
3594+
struct OmpInitializerExpression : public OmpStylizedExpression {
3595+
INHERITED_WRAPPER_CLASS_BOILERPLATE(
3596+
OmpInitializerExpression, OmpStylizedExpression);
3597+
static llvm::ArrayRef<CharBlock> Variables();
35553598
};
35563599

35573600
inline namespace arguments {
@@ -4558,10 +4601,10 @@ struct OmpInitializerProc {
45584601
TUPLE_CLASS_BOILERPLATE(OmpInitializerProc);
45594602
std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
45604603
};
4604+
45614605
// Initialization for declare reduction construct
45624606
struct OmpInitializerClause {
4563-
UNION_CLASS_BOILERPLATE(OmpInitializerClause);
4564-
std::variant<OmpInitializerProc, AssignmentStmt> u;
4607+
WRAPPER_CLASS_BOILERPLATE(OmpInitializerClause, OmpInitializerExpression);
45654608
};
45664609

45674610
// Ref: [4.5:199-201], [5.0:288-290], [5.1:321-322], [5.2:115-117]

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 165 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -275,18 +275,21 @@ struct SpecificModifierParser {
275275

276276
// --- Iterator helpers -----------------------------------------------
277277

278+
static EntityDecl MakeEntityDecl(ObjectName &&name) {
279+
return EntityDecl(
280+
/*ObjectName=*/std::move(name), std::optional<ArraySpec>{},
281+
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
282+
std::optional<Initialization>{});
283+
}
284+
278285
// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
279286
// specified then the type of that iterator is default integer.
280287
// [5.0:49:14] The iterator-type must be an integer type.
281288
static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
282289
std::list<EntityDecl> entities;
283290

284291
for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
285-
EntityDecl entityDecl(
286-
/*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
287-
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
288-
std::optional<Initialization>{});
289-
entities.push_back(std::move(entityDecl));
292+
entities.push_back(MakeEntityDecl(std::move(*iter)));
290293
}
291294
return entities;
292295
}
@@ -306,6 +309,157 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
306309
makeEntityList(std::move(names)));
307310
}
308311

312+
// --- Stylized expression handling -----------------------------------
313+
314+
template <typename A> struct NeverParser {
315+
using resultType = A;
316+
std::optional<resultType> Parse(ParseState &state) const {
317+
// Always fail, but without any messages.
318+
return std::nullopt;
319+
}
320+
};
321+
322+
template <typename A> constexpr auto never() { return NeverParser<A>{}; }
323+
324+
template <typename A, typename B = void> struct NullParser;
325+
template <typename B> struct NullParser<std::optional<B>> {
326+
using resultType = std::optional<B>;
327+
std::optional<resultType> Parse(ParseState &) const {
328+
return resultType{std::nullopt};
329+
}
330+
};
331+
332+
template <typename A> constexpr auto null() { return NullParser<A>{}; }
333+
334+
// OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and
335+
// don't correspond to anything in the source. Their parsers should still
336+
// exist, but they should never be executed.
337+
TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))
338+
339+
TYPE_PARSER( //
340+
construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||
341+
construct<OmpStylizedInstance::Instance>(
342+
sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},
343+
null<std::optional<CallStmt::Chevrons>>(),
344+
parenthesized(optionalList(actualArgSpec))))) ||
345+
construct<OmpStylizedInstance::Instance>(indirect(expr)))
346+
347+
TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))
348+
349+
struct OmpStylizedExpressionParser {
350+
using resultType = OmpStylizedExpression;
351+
352+
std::optional<resultType> Parse(ParseState &state) const {
353+
auto *saved{new ParseState(state)};
354+
auto getSource{verbatim(Parser<OmpStylizedInstance::Instance>{} >> ok)};
355+
if (auto &&ok{getSource.Parse(state)}) {
356+
OmpStylizedExpression result{std::list<OmpStylizedInstance>{}};
357+
result.source = ok->source;
358+
result.state = saved;
359+
// result.v remains empty
360+
return std::move(result);
361+
}
362+
delete saved;
363+
return std::nullopt;
364+
}
365+
};
366+
367+
static void Instantiate(OmpStylizedExpression &ose,
368+
llvm::ArrayRef<const OmpTypeName *> types, llvm::ArrayRef<CharBlock> vars) {
369+
assert(types.size() == vars.size() && "List size mismatch");
370+
ParseState state{DEREF(ose.state)};
371+
372+
std::list<OmpStylizedDeclaration> decls;
373+
for (auto [type, var] : llvm::zip(types, vars)) {
374+
decls.emplace_back(OmpStylizedDeclaration{
375+
common::Reference(*type), MakeEntityDecl(Name{var})});
376+
}
377+
378+
if (auto &&instance{Parser<OmpStylizedInstance::Instance>{}.Parse(state)}) {
379+
ose.v.emplace_back(
380+
OmpStylizedInstance{std::move(decls), std::move(*instance)});
381+
}
382+
}
383+
384+
static void InstantiateForTypes(OmpStylizedExpression &ose,
385+
const OmpTypeNameList &typeNames, llvm::ArrayRef<CharBlock> vars) {
386+
// The variables "vars" need to be declared with the same type.
387+
// For each type in the type list, splat the type into a vector of
388+
// the same size as the variable list, and pass it to Instantiate.
389+
for (const OmpTypeName &t : typeNames.v) {
390+
std::vector<const OmpTypeName *> types(vars.size(), &t);
391+
Instantiate(ose, types, vars);
392+
}
393+
}
394+
395+
static void InstantiateDeclareReduction(OmpDirectiveSpecification &spec) {
396+
// There can be arguments/clauses that don't make sense, that analysis
397+
// is left until semantic checks. Tolerate any unexpected stuff.
398+
auto *rspec{GetFirstArgument<OmpReductionSpecifier>(spec)};
399+
if (!rspec) {
400+
return;
401+
}
402+
403+
const OmpTypeNameList *typeNames{nullptr};
404+
405+
if (auto *cexpr{GetCombinerExpr(*rspec)}) {
406+
typeNames = &std::get<OmpTypeNameList>(rspec->t);
407+
408+
InstantiateForTypes(const_cast<OmpCombinerExpression &>(*cexpr), *typeNames,
409+
OmpCombinerExpression::Variables());
410+
delete cexpr->state;
411+
} else {
412+
// If there are no types, there is nothing else to do.
413+
return;
414+
}
415+
416+
for (const OmpClause &clause : spec.Clauses().v) {
417+
llvm::omp::Clause id{clause.Id()};
418+
if (id == llvm::omp::Clause::OMPC_initializer) {
419+
if (auto *iexpr{GetInitializerExpr(clause)}) {
420+
InstantiateForTypes(const_cast<OmpInitializerExpression &>(*iexpr),
421+
*typeNames, OmpInitializerExpression::Variables());
422+
delete iexpr->state;
423+
}
424+
}
425+
}
426+
}
427+
428+
static void InstantiateStylizedDirective(OmpDirectiveSpecification &spec) {
429+
const OmpDirectiveName &dirName{spec.DirName()};
430+
if (dirName.v == llvm::omp::Directive::OMPD_declare_reduction) {
431+
InstantiateDeclareReduction(spec);
432+
}
433+
}
434+
435+
template <typename P,
436+
typename = std::enable_if_t<
437+
std::is_same_v<typename P::resultType, OmpDirectiveSpecification>>>
438+
struct OmpStylizedInstanceCreator {
439+
using resultType = OmpDirectiveSpecification;
440+
constexpr OmpStylizedInstanceCreator(P p) : parser_(p) {}
441+
442+
std::optional<resultType> Parse(ParseState &state) const {
443+
if (auto &&spec{parser_.Parse(state)}) {
444+
InstantiateStylizedDirective(*spec);
445+
return std::move(spec);
446+
}
447+
return std::nullopt;
448+
}
449+
450+
private:
451+
const P parser_;
452+
};
453+
454+
template <typename P>
455+
OmpStylizedInstanceCreator(P) -> OmpStylizedInstanceCreator<P>;
456+
457+
// --- Parsers for types ----------------------------------------------
458+
459+
TYPE_PARSER( //
460+
sourced(construct<OmpTypeName>(Parser<DeclarationTypeSpec>{})) ||
461+
sourced(construct<OmpTypeName>(Parser<TypeSpec>{})))
462+
309463
// --- Parsers for arguments ------------------------------------------
310464

311465
// At the moment these are only directive arguments. This is needed for
@@ -366,10 +520,6 @@ struct OmpArgumentListParser {
366520
}
367521
};
368522

369-
TYPE_PARSER( //
370-
construct<OmpTypeName>(Parser<DeclarationTypeSpec>{}) ||
371-
construct<OmpTypeName>(Parser<TypeSpec>{}))
372-
373523
// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
374524
TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
375525
construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
@@ -1065,7 +1215,8 @@ TYPE_PARSER(construct<OmpOtherwiseClause>(
10651215

10661216
TYPE_PARSER(construct<OmpWhenClause>(
10671217
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
1068-
maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
1218+
maybe(indirect(
1219+
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{})))))
10691220

10701221
// OMP 5.2 12.6.1 grainsize([ prescriptiveness :] scalar-integer-expression)
10711222
TYPE_PARSER(construct<OmpGrainsizeClause>(
@@ -1780,9 +1931,7 @@ TYPE_PARSER(
17801931
TYPE_PARSER(construct<OmpInitializerProc>(Parser<ProcedureDesignator>{},
17811932
parenthesized(many(maybe(","_tok) >> Parser<ActualArgSpec>{}))))
17821933

1783-
TYPE_PARSER(construct<OmpInitializerClause>(
1784-
construct<OmpInitializerClause>(assignmentStmt) ||
1785-
construct<OmpInitializerClause>(Parser<OmpInitializerProc>{})))
1934+
TYPE_PARSER(construct<OmpInitializerClause>(Parser<OmpInitializerExpression>{}))
17861935

17871936
// OpenMP 5.2: 7.5.4 Declare Variant directive
17881937
TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
@@ -1794,7 +1943,7 @@ TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
17941943
TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
17951944
predicated(Parser<OmpDirectiveName>{},
17961945
IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=
1797-
Parser<OmpDirectiveSpecification>{})))
1946+
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{}))))
17981947

17991948
// 2.10.6 Declare Target Construct
18001949
TYPE_PARSER(sourced(construct<OpenMPDeclareTargetConstruct>(
@@ -1832,8 +1981,8 @@ TYPE_PARSER(sourced(construct<OpenMPDeclareMapperConstruct>(
18321981
IsDirective(llvm::omp::Directive::OMPD_declare_mapper)) >=
18331982
Parser<OmpDirectiveSpecification>{})))
18341983

1835-
TYPE_PARSER(construct<OmpCombinerExpression>(Parser<AssignmentStmt>{}) ||
1836-
construct<OmpCombinerExpression>(Parser<FunctionReference>{}))
1984+
TYPE_PARSER(construct<OmpCombinerExpression>(OmpStylizedExpressionParser{}))
1985+
TYPE_PARSER(construct<OmpInitializerExpression>(OmpStylizedExpressionParser{}))
18371986

18381987
TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(
18391988
OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))

flang/lib/Parser/openmp-utils.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,16 @@ const BlockConstruct *GetFortranBlockConstruct(
7474
return nullptr;
7575
}
7676

77+
const OmpCombinerExpression *GetCombinerExpr(
78+
const OmpReductionSpecifier &rspec) {
79+
return addr_if(std::get<std::optional<OmpCombinerExpression>>(rspec.t));
80+
}
81+
82+
const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init) {
83+
if (auto *wrapped{std::get_if<OmpClause::Initializer>(&init.u)}) {
84+
return &wrapped->v.v;
85+
}
86+
return nullptr;
87+
}
88+
7789
} // namespace Fortran::parser::omp

0 commit comments

Comments
 (0)