Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions flang/include/flang/Parser/dump-parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,10 @@ class ParseTreeDumper {
NODE_ENUM(OmpSeverityClause, Severity)
NODE(parser, OmpStepComplexModifier)
NODE(parser, OmpStepSimpleModifier)
NODE(parser, OmpStylizedDeclaration)
NODE(parser, OmpStylizedExpression)
NODE(parser, OmpStylizedInstance)
NODE(OmpStylizedInstance, Instance)
NODE(parser, OmpTaskDependenceType)
NODE_ENUM(OmpTaskDependenceType, Value)
NODE(parser, OmpTaskReductionClause)
Expand Down
22 changes: 22 additions & 0 deletions flang/include/flang/Parser/openmp-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@

namespace Fortran::parser::omp {

template <typename T> constexpr auto addr_if(std::optional<T> &x) {
return x ? &*x : nullptr;
}
template <typename T> constexpr auto addr_if(const std::optional<T> &x) {
return x ? &*x : nullptr;
}

namespace detail {
using D = llvm::omp::Directive;

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

const OmpObjectList *GetOmpObjectList(const OmpClause &clause);

template <typename T>
const T *GetFirstArgument(const OmpDirectiveSpecification &spec) {
for (const OmpArgument &arg : spec.Arguments().v) {
if (auto *t{std::get_if<T>(&arg.u)}) {
return t;
}
}
return nullptr;
}

const BlockConstruct *GetFortranBlockConstruct(
const ExecutionPartConstruct &epc);

const OmpCombinerExpression *GetCombinerExpr(
const OmpReductionSpecifier &rspec);
const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init);

} // namespace Fortran::parser::omp

#endif // FORTRAN_PARSER_OPENMP_UTILS_H
53 changes: 48 additions & 5 deletions flang/include/flang/Parser/parse-tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@
#include "provenance.h"
#include "flang/Common/idioms.h"
#include "flang/Common/indirection.h"
#include "flang/Common/reference.h"
#include "flang/Support/Fortran.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Frontend/OpenACC/ACC.h.inc"
#include "llvm/Frontend/OpenMP/OMP.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
Expand Down Expand Up @@ -3504,6 +3506,8 @@ struct OmpDirectiveName {

// type-name list item
struct OmpTypeName {
CharBlock source;
mutable const semantics::DeclTypeSpec *declTypeSpec{nullptr};
UNION_CLASS_BOILERPLATE(OmpTypeName);
std::variant<TypeSpec, DeclarationTypeSpec> u;
};
Expand Down Expand Up @@ -3532,6 +3536,32 @@ struct OmpObjectList {
WRAPPER_CLASS_BOILERPLATE(OmpObjectList, std::list<OmpObject>);
};

struct OmpStylizedDeclaration {
COPY_AND_ASSIGN_BOILERPLATE(OmpStylizedDeclaration);
using EmptyTrait = std::true_type;
common::Reference<const OmpTypeName> type;
EntityDecl var;
};

struct OmpStylizedInstance {
struct Instance {
UNION_CLASS_BOILERPLATE(Instance);
std::variant<AssignmentStmt, CallStmt, common::Indirection<Expr>>
u;
};
TUPLE_CLASS_BOILERPLATE(OmpStylizedInstance);
std::tuple<std::list<OmpStylizedDeclaration>, Instance> t;
};

class ParseState;

struct OmpStylizedExpression {
CharBlock source;
const ParseState *state{nullptr};
WRAPPER_CLASS_BOILERPLATE(
OmpStylizedExpression, std::list<OmpStylizedInstance>);
};

// Ref: [4.5:201-207], [5.0:293-299], [5.1:325-331], [5.2:124]
//
// reduction-identifier ->
Expand All @@ -3549,9 +3579,22 @@ struct OmpReductionIdentifier {
// combiner-expression -> // since 4.5
// assignment-statement |
// function-reference
struct OmpCombinerExpression {
UNION_CLASS_BOILERPLATE(OmpCombinerExpression);
std::variant<AssignmentStmt, FunctionReference> u;
struct OmpCombinerExpression : public OmpStylizedExpression {
INHERITED_WRAPPER_CLASS_BOILERPLATE(
OmpCombinerExpression, OmpStylizedExpression);
static llvm::ArrayRef<CharBlock> Variables();
};

// Ref: [4.5:222:7-8], [5.0:305:28-29], [5.1:337:20-21], [5.2:127:6-8],
// [6.0:242:3-5]
//
// initializer-expression -> // since 4.5
// OMP_PRIV = expression |
// subroutine-name(argument-list)
struct OmpInitializerExpression : public OmpStylizedExpression {
INHERITED_WRAPPER_CLASS_BOILERPLATE(
OmpInitializerExpression, OmpStylizedExpression);
static llvm::ArrayRef<CharBlock> Variables();
};

inline namespace arguments {
Expand Down Expand Up @@ -4558,10 +4601,10 @@ struct OmpInitializerProc {
TUPLE_CLASS_BOILERPLATE(OmpInitializerProc);
std::tuple<ProcedureDesignator, std::list<ActualArgSpec>> t;
};

// Initialization for declare reduction construct
struct OmpInitializerClause {
UNION_CLASS_BOILERPLATE(OmpInitializerClause);
std::variant<OmpInitializerProc, AssignmentStmt> u;
WRAPPER_CLASS_BOILERPLATE(OmpInitializerClause, OmpInitializerExpression);
};

// Ref: [4.5:199-201], [5.0:288-290], [5.1:321-322], [5.2:115-117]
Expand Down
181 changes: 165 additions & 16 deletions flang/lib/Parser/openmp-parsers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,18 +275,21 @@ struct SpecificModifierParser {

// --- Iterator helpers -----------------------------------------------

static EntityDecl MakeEntityDecl(ObjectName &&name) {
return EntityDecl(
/*ObjectName=*/std::move(name), std::optional<ArraySpec>{},
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
std::optional<Initialization>{});
}

// [5.0:47:17-18] In an iterator-specifier, if the iterator-type is not
// specified then the type of that iterator is default integer.
// [5.0:49:14] The iterator-type must be an integer type.
static std::list<EntityDecl> makeEntityList(std::list<ObjectName> &&names) {
std::list<EntityDecl> entities;

for (auto iter = names.begin(), end = names.end(); iter != end; ++iter) {
EntityDecl entityDecl(
/*ObjectName=*/std::move(*iter), std::optional<ArraySpec>{},
std::optional<CoarraySpec>{}, std::optional<CharLength>{},
std::optional<Initialization>{});
entities.push_back(std::move(entityDecl));
entities.push_back(MakeEntityDecl(std::move(*iter)));
}
return entities;
}
Expand All @@ -306,6 +309,157 @@ static TypeDeclarationStmt makeIterSpecDecl(std::list<ObjectName> &&names) {
makeEntityList(std::move(names)));
}

// --- Stylized expression handling -----------------------------------

template <typename A> struct NeverParser {
using resultType = A;
std::optional<resultType> Parse(ParseState &state) const {
// Always fail, but without any messages.
return std::nullopt;
}
};

template <typename A> constexpr auto never() { return NeverParser<A>{}; }

template <typename A, typename B = void> struct NullParser;
template <typename B> struct NullParser<std::optional<B>> {
using resultType = std::optional<B>;
std::optional<resultType> Parse(ParseState &) const {
return resultType{std::nullopt};
}
};

template <typename A> constexpr auto null() { return NullParser<A>{}; }

// OmpStylizedDeclaration and OmpStylizedInstance are helper classes, and
// don't correspond to anything in the source. Their parsers should still
// exist, but they should never be executed.
TYPE_PARSER(construct<OmpStylizedDeclaration>(never<OmpStylizedDeclaration>()))

TYPE_PARSER( //
construct<OmpStylizedInstance::Instance>(Parser<AssignmentStmt>{}) ||
construct<OmpStylizedInstance::Instance>(
sourced(construct<CallStmt>(Parser<ProcedureDesignator>{},
null<std::optional<CallStmt::Chevrons>>(),
parenthesized(optionalList(actualArgSpec))))) ||
construct<OmpStylizedInstance::Instance>(indirect(expr)))

TYPE_PARSER(construct<OmpStylizedInstance>(never<OmpStylizedInstance>()))

struct OmpStylizedExpressionParser {
using resultType = OmpStylizedExpression;

std::optional<resultType> Parse(ParseState &state) const {
auto *saved{new ParseState(state)};
auto getSource{verbatim(Parser<OmpStylizedInstance::Instance>{} >> ok)};
if (auto &&ok{getSource.Parse(state)}) {
OmpStylizedExpression result{std::list<OmpStylizedInstance>{}};
result.source = ok->source;
result.state = saved;
// result.v remains empty
return std::move(result);
}
delete saved;
return std::nullopt;
}
};

static void Instantiate(OmpStylizedExpression &ose,
llvm::ArrayRef<const OmpTypeName *> types, llvm::ArrayRef<CharBlock> vars) {
assert(types.size() == vars.size() && "List size mismatch");
ParseState state{DEREF(ose.state)};

std::list<OmpStylizedDeclaration> decls;
for (auto [type, var] : llvm::zip(types, vars)) {
decls.emplace_back(OmpStylizedDeclaration{
common::Reference(*type), MakeEntityDecl(Name{var})});
}

if (auto &&instance{Parser<OmpStylizedInstance::Instance>{}.Parse(state)}) {
ose.v.emplace_back(
OmpStylizedInstance{std::move(decls), std::move(*instance)});
}
}

static void InstantiateForTypes(OmpStylizedExpression &ose,
const OmpTypeNameList &typeNames, llvm::ArrayRef<CharBlock> vars) {
// The variables "vars" need to be declared with the same type.
// For each type in the type list, splat the type into a vector of
// the same size as the variable list, and pass it to Instantiate.
for (const OmpTypeName &t : typeNames.v) {
std::vector<const OmpTypeName *> types(vars.size(), &t);
Instantiate(ose, types, vars);
}
}

static void InstantiateDeclareReduction(OmpDirectiveSpecification &spec) {
// There can be arguments/clauses that don't make sense, that analysis
// is left until semantic checks. Tolerate any unexpected stuff.
auto *rspec{GetFirstArgument<OmpReductionSpecifier>(spec)};
if (!rspec) {
return;
}

const OmpTypeNameList *typeNames{nullptr};

if (auto *cexpr{GetCombinerExpr(*rspec)}) {
typeNames = &std::get<OmpTypeNameList>(rspec->t);

InstantiateForTypes(const_cast<OmpCombinerExpression &>(*cexpr), *typeNames,
OmpCombinerExpression::Variables());
delete cexpr->state;
} else {
// If there are no types, there is nothing else to do.
return;
}

for (const OmpClause &clause : spec.Clauses().v) {
llvm::omp::Clause id{clause.Id()};
if (id == llvm::omp::Clause::OMPC_initializer) {
if (auto *iexpr{GetInitializerExpr(clause)}) {
InstantiateForTypes(const_cast<OmpInitializerExpression &>(*iexpr),
*typeNames, OmpInitializerExpression::Variables());
delete iexpr->state;
}
}
}
}

static void InstantiateStylizedDirective(OmpDirectiveSpecification &spec) {
const OmpDirectiveName &dirName{spec.DirName()};
if (dirName.v == llvm::omp::Directive::OMPD_declare_reduction) {
InstantiateDeclareReduction(spec);
}
}

template <typename P,
typename = std::enable_if_t<
std::is_same_v<typename P::resultType, OmpDirectiveSpecification>>>
struct OmpStylizedInstanceCreator {
using resultType = OmpDirectiveSpecification;
constexpr OmpStylizedInstanceCreator(P p) : parser_(p) {}

std::optional<resultType> Parse(ParseState &state) const {
if (auto &&spec{parser_.Parse(state)}) {
InstantiateStylizedDirective(*spec);
return std::move(spec);
}
return std::nullopt;
}

private:
const P parser_;
};

template <typename P>
OmpStylizedInstanceCreator(P) -> OmpStylizedInstanceCreator<P>;

// --- Parsers for types ----------------------------------------------

TYPE_PARSER( //
sourced(construct<OmpTypeName>(Parser<DeclarationTypeSpec>{})) ||
sourced(construct<OmpTypeName>(Parser<TypeSpec>{})))

// --- Parsers for arguments ------------------------------------------

// At the moment these are only directive arguments. This is needed for
Expand Down Expand Up @@ -366,10 +520,6 @@ struct OmpArgumentListParser {
}
};

TYPE_PARSER( //
construct<OmpTypeName>(Parser<DeclarationTypeSpec>{}) ||
construct<OmpTypeName>(Parser<TypeSpec>{}))

// 2.15.3.6 REDUCTION (reduction-identifier: variable-name-list)
TYPE_PARSER(construct<OmpReductionIdentifier>(Parser<DefinedOperator>{}) ||
construct<OmpReductionIdentifier>(Parser<ProcedureDesignator>{}))
Expand Down Expand Up @@ -1065,7 +1215,8 @@ TYPE_PARSER(construct<OmpOtherwiseClause>(

TYPE_PARSER(construct<OmpWhenClause>(
maybe(nonemptyList(Parser<OmpWhenClause::Modifier>{}) / ":"),
maybe(indirect(Parser<OmpDirectiveSpecification>{}))))
maybe(indirect(
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{})))))

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

TYPE_PARSER(construct<OmpInitializerClause>(
construct<OmpInitializerClause>(assignmentStmt) ||
construct<OmpInitializerClause>(Parser<OmpInitializerProc>{})))
TYPE_PARSER(construct<OmpInitializerClause>(Parser<OmpInitializerExpression>{}))

// OpenMP 5.2: 7.5.4 Declare Variant directive
TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
Expand All @@ -1794,7 +1943,7 @@ TYPE_PARSER(sourced(construct<OmpDeclareVariantDirective>(
TYPE_PARSER(sourced(construct<OpenMPDeclareReductionConstruct>(
predicated(Parser<OmpDirectiveName>{},
IsDirective(llvm::omp::Directive::OMPD_declare_reduction)) >=
Parser<OmpDirectiveSpecification>{})))
OmpStylizedInstanceCreator(Parser<OmpDirectiveSpecification>{}))))

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

TYPE_PARSER(construct<OmpCombinerExpression>(Parser<AssignmentStmt>{}) ||
construct<OmpCombinerExpression>(Parser<FunctionReference>{}))
TYPE_PARSER(construct<OmpCombinerExpression>(OmpStylizedExpressionParser{}))
TYPE_PARSER(construct<OmpInitializerExpression>(OmpStylizedExpressionParser{}))

TYPE_PARSER(sourced(construct<OpenMPCriticalConstruct>(
OmpBlockConstructParser{llvm::omp::Directive::OMPD_critical})))
Expand Down
12 changes: 12 additions & 0 deletions flang/lib/Parser/openmp-utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,16 @@ const BlockConstruct *GetFortranBlockConstruct(
return nullptr;
}

const OmpCombinerExpression *GetCombinerExpr(
const OmpReductionSpecifier &rspec) {
return addr_if(std::get<std::optional<OmpCombinerExpression>>(rspec.t));
}

const OmpInitializerExpression *GetInitializerExpr(const OmpClause &init) {
if (auto *wrapped{std::get_if<OmpClause::Initializer>(&init.u)}) {
return &wrapped->v.v;
}
return nullptr;
}

} // namespace Fortran::parser::omp
Loading
Loading