Implement parsing of the AFFINITY clause on TASK construct, conversion from the parser class to omp::Clause. Lowering to HLFIR is unsupported, a TODO message is displayed.
1332 lines
44 KiB
C++
1332 lines
44 KiB
C++
//===-- Clauses.cpp -- OpenMP clause handling -----------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Clauses.h"
|
|
|
|
#include "flang/Common/idioms.h"
|
|
#include "flang/Evaluate/expression.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/expression.h"
|
|
#include "flang/Semantics/symbol.h"
|
|
|
|
#include "llvm/Frontend/OpenMP/OMPConstants.h"
|
|
|
|
#include <list>
|
|
#include <optional>
|
|
#include <tuple>
|
|
#include <utility>
|
|
#include <variant>
|
|
|
|
namespace Fortran::lower::omp {
|
|
using SymbolWithDesignator = std::tuple<semantics::Symbol *, MaybeExpr>;
|
|
|
|
struct SymbolAndDesignatorExtractor {
|
|
template <typename T>
|
|
static T &&AsRvalueRef(T &&t) {
|
|
return std::move(t);
|
|
}
|
|
template <typename T>
|
|
static T AsRvalueRef(const T &t) {
|
|
return t;
|
|
}
|
|
|
|
static semantics::Symbol *symbol_addr(const evaluate::SymbolRef &ref) {
|
|
// Symbols cannot be created after semantic checks, so all symbol
|
|
// pointers that are non-null must point to one of those pre-existing
|
|
// objects. Throughout the code, symbols are often pointed to by
|
|
// non-const pointers, so there is no harm in casting the constness
|
|
// away.
|
|
return const_cast<semantics::Symbol *>(&ref.get());
|
|
}
|
|
|
|
template <typename T>
|
|
static SymbolWithDesignator visit(T &&) {
|
|
// Use this to see missing overloads:
|
|
// llvm::errs() << "NULL: " << __PRETTY_FUNCTION__ << '\n';
|
|
return SymbolWithDesignator{};
|
|
}
|
|
|
|
template <typename T>
|
|
static SymbolWithDesignator visit(const evaluate::Designator<T> &e) {
|
|
return std::make_tuple(symbol_addr(*e.GetLastSymbol()),
|
|
evaluate::AsGenericExpr(AsRvalueRef(e)));
|
|
}
|
|
|
|
static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) {
|
|
return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt);
|
|
}
|
|
|
|
template <typename T>
|
|
static SymbolWithDesignator visit(const evaluate::Expr<T> &e) {
|
|
return Fortran::common::visit([](auto &&s) { return visit(s); }, e.u);
|
|
}
|
|
|
|
static void verify(const SymbolWithDesignator &sd) {
|
|
const semantics::Symbol *symbol = std::get<0>(sd);
|
|
assert(symbol && "Expecting symbol");
|
|
auto &maybeDsg = std::get<1>(sd);
|
|
if (!maybeDsg)
|
|
return; // Symbol with no designator -> OK
|
|
std::optional<evaluate::DataRef> maybeRef =
|
|
evaluate::ExtractDataRef(*maybeDsg);
|
|
if (maybeRef) {
|
|
if (&maybeRef->GetLastSymbol() == symbol)
|
|
return; // Symbol with a designator for it -> OK
|
|
llvm_unreachable("Expecting designator for given symbol");
|
|
} else {
|
|
// This could still be a Substring or ComplexPart, but at least Substring
|
|
// is not allowed in OpenMP.
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
maybeDsg->dump();
|
|
#endif
|
|
llvm_unreachable("Expecting DataRef designator");
|
|
}
|
|
}
|
|
};
|
|
|
|
SymbolWithDesignator getSymbolAndDesignator(const MaybeExpr &expr) {
|
|
if (!expr)
|
|
return SymbolWithDesignator{};
|
|
return Fortran::common::visit(
|
|
[](auto &&s) { return SymbolAndDesignatorExtractor::visit(s); }, expr->u);
|
|
}
|
|
|
|
Object makeObject(const parser::Name &name,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
assert(name.symbol && "Expecting Symbol");
|
|
return Object{name.symbol, std::nullopt};
|
|
}
|
|
|
|
Object makeObject(const parser::Designator &dsg,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
evaluate::ExpressionAnalyzer ea{semaCtx};
|
|
SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(dsg));
|
|
SymbolAndDesignatorExtractor::verify(sd);
|
|
return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
|
|
}
|
|
|
|
Object makeObject(const parser::StructureComponent &comp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
evaluate::ExpressionAnalyzer ea{semaCtx};
|
|
SymbolWithDesignator sd = getSymbolAndDesignator(ea.Analyze(comp));
|
|
SymbolAndDesignatorExtractor::verify(sd);
|
|
return Object{std::get<0>(sd), std::move(std::get<1>(sd))};
|
|
}
|
|
|
|
Object makeObject(const parser::OmpObject &object,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// If object is a common block, expression analyzer won't be able to
|
|
// do anything.
|
|
if (const auto *name = std::get_if<parser::Name>(&object.u)) {
|
|
assert(name->symbol && "Expecting Symbol");
|
|
return Object{name->symbol, std::nullopt};
|
|
}
|
|
// OmpObject is std::variant<Designator, /*common block*/ Name>;
|
|
return makeObject(std::get<parser::Designator>(object.u), semaCtx);
|
|
}
|
|
|
|
std::optional<Object> getBaseObject(const Object &object,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// If it's just the symbol, then there is no base.
|
|
if (!object.ref())
|
|
return std::nullopt;
|
|
|
|
auto maybeRef = evaluate::ExtractDataRef(*object.ref());
|
|
if (!maybeRef)
|
|
return std::nullopt;
|
|
|
|
evaluate::DataRef ref = *maybeRef;
|
|
|
|
if (std::get_if<evaluate::SymbolRef>(&ref.u)) {
|
|
return std::nullopt;
|
|
} else if (auto *comp = std::get_if<evaluate::Component>(&ref.u)) {
|
|
const evaluate::DataRef &base = comp->base();
|
|
return Object{
|
|
SymbolAndDesignatorExtractor::symbol_addr(base.GetLastSymbol()),
|
|
evaluate::AsGenericExpr(
|
|
SymbolAndDesignatorExtractor::AsRvalueRef(base))};
|
|
} else if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u)) {
|
|
const evaluate::NamedEntity &base = arr->base();
|
|
evaluate::ExpressionAnalyzer ea{semaCtx};
|
|
if (auto *comp = base.UnwrapComponent()) {
|
|
return Object{SymbolAndDesignatorExtractor::symbol_addr(comp->symbol()),
|
|
ea.Designate(evaluate::DataRef{
|
|
SymbolAndDesignatorExtractor::AsRvalueRef(*comp)})};
|
|
} else if (base.UnwrapSymbolRef()) {
|
|
return std::nullopt;
|
|
}
|
|
} else {
|
|
assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u) &&
|
|
"Unexpected variant alternative");
|
|
llvm_unreachable("Coarray reference not supported at the moment");
|
|
}
|
|
return std::nullopt;
|
|
}
|
|
|
|
// Helper macros
|
|
#define MAKE_EMPTY_CLASS(cls, from_cls) \
|
|
cls make(const parser::OmpClause::from_cls &, \
|
|
semantics::SemanticsContext &) { \
|
|
static_assert(cls::EmptyTrait::value); \
|
|
return cls{}; \
|
|
} \
|
|
[[maybe_unused]] extern int xyzzy_semicolon_absorber
|
|
|
|
#define MAKE_INCOMPLETE_CLASS(cls, from_cls) \
|
|
cls make(const parser::OmpClause::from_cls &, \
|
|
semantics::SemanticsContext &) { \
|
|
static_assert(cls::IncompleteTrait::value); \
|
|
return cls{}; \
|
|
} \
|
|
[[maybe_unused]] extern int xyzzy_semicolon_absorber
|
|
|
|
#define MS(x, y) CLAUSET_SCOPED_ENUM_MEMBER_CONVERT(x, y)
|
|
#define MU(x, y) CLAUSET_UNSCOPED_ENUM_MEMBER_CONVERT(x, y)
|
|
|
|
namespace clause {
|
|
MAKE_EMPTY_CLASS(AcqRel, AcqRel);
|
|
MAKE_EMPTY_CLASS(Acquire, Acquire);
|
|
MAKE_EMPTY_CLASS(Capture, Capture);
|
|
MAKE_EMPTY_CLASS(Compare, Compare);
|
|
MAKE_EMPTY_CLASS(DynamicAllocators, DynamicAllocators);
|
|
MAKE_EMPTY_CLASS(Full, Full);
|
|
MAKE_EMPTY_CLASS(Inbranch, Inbranch);
|
|
MAKE_EMPTY_CLASS(Mergeable, Mergeable);
|
|
MAKE_EMPTY_CLASS(Nogroup, Nogroup);
|
|
MAKE_EMPTY_CLASS(NoOpenmp, NoOpenmp);
|
|
MAKE_EMPTY_CLASS(NoOpenmpRoutines, NoOpenmpRoutines);
|
|
MAKE_EMPTY_CLASS(NoParallelism, NoParallelism);
|
|
MAKE_EMPTY_CLASS(Notinbranch, Notinbranch);
|
|
MAKE_EMPTY_CLASS(Nowait, Nowait);
|
|
MAKE_EMPTY_CLASS(OmpxAttribute, OmpxAttribute);
|
|
MAKE_EMPTY_CLASS(OmpxBare, OmpxBare);
|
|
MAKE_EMPTY_CLASS(Read, Read);
|
|
MAKE_EMPTY_CLASS(Relaxed, Relaxed);
|
|
MAKE_EMPTY_CLASS(Release, Release);
|
|
MAKE_EMPTY_CLASS(ReverseOffload, ReverseOffload);
|
|
MAKE_EMPTY_CLASS(SeqCst, SeqCst);
|
|
MAKE_EMPTY_CLASS(Simd, Simd);
|
|
MAKE_EMPTY_CLASS(Threads, Threads);
|
|
MAKE_EMPTY_CLASS(UnifiedAddress, UnifiedAddress);
|
|
MAKE_EMPTY_CLASS(UnifiedSharedMemory, UnifiedSharedMemory);
|
|
MAKE_EMPTY_CLASS(Unknown, Unknown);
|
|
MAKE_EMPTY_CLASS(Untied, Untied);
|
|
MAKE_EMPTY_CLASS(Weak, Weak);
|
|
MAKE_EMPTY_CLASS(Write, Write);
|
|
|
|
// Artificial clauses
|
|
MAKE_EMPTY_CLASS(CancellationConstructType, CancellationConstructType);
|
|
MAKE_EMPTY_CLASS(Depobj, Depobj);
|
|
MAKE_EMPTY_CLASS(Flush, Flush);
|
|
MAKE_EMPTY_CLASS(MemoryOrder, MemoryOrder);
|
|
MAKE_EMPTY_CLASS(Threadprivate, Threadprivate);
|
|
|
|
MAKE_INCOMPLETE_CLASS(AdjustArgs, AdjustArgs);
|
|
MAKE_INCOMPLETE_CLASS(AppendArgs, AppendArgs);
|
|
MAKE_INCOMPLETE_CLASS(Match, Match);
|
|
// MAKE_INCOMPLETE_CLASS(Otherwise, ); // missing-in-parser
|
|
MAKE_INCOMPLETE_CLASS(When, When);
|
|
|
|
List<IteratorSpecifier>
|
|
makeIteratorSpecifiers(const parser::OmpIteratorSpecifier &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
List<IteratorSpecifier> specifiers;
|
|
|
|
auto &[begin, end, step] = std::get<parser::SubscriptTriplet>(inp.t).t;
|
|
assert(begin && end && "Expecting begin/end values");
|
|
evaluate::ExpressionAnalyzer ea{semaCtx};
|
|
|
|
MaybeExpr rbegin{ea.Analyze(*begin)}, rend{ea.Analyze(*end)};
|
|
MaybeExpr rstep;
|
|
if (step)
|
|
rstep = ea.Analyze(*step);
|
|
|
|
assert(rbegin && rend && "Unable to get range bounds");
|
|
Range range{{*rbegin, *rend, rstep}};
|
|
|
|
auto &tds = std::get<parser::TypeDeclarationStmt>(inp.t);
|
|
auto &entities = std::get<std::list<parser::EntityDecl>>(tds.t);
|
|
for (const parser::EntityDecl &ed : entities) {
|
|
auto &name = std::get<parser::ObjectName>(ed.t);
|
|
assert(name.symbol && "Expecting symbol for iterator variable");
|
|
auto *stype = name.symbol->GetType();
|
|
assert(stype && "Expecting symbol type");
|
|
IteratorSpecifier spec{{evaluate::DynamicType::From(*stype),
|
|
makeObject(name, semaCtx), range}};
|
|
specifiers.emplace_back(std::move(spec));
|
|
}
|
|
|
|
return specifiers;
|
|
}
|
|
|
|
Iterator makeIterator(const parser::OmpIteratorModifier &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
Iterator iterator;
|
|
for (auto &&spec : inp.v)
|
|
llvm::append_range(iterator, makeIteratorSpecifiers(spec, semaCtx));
|
|
return iterator;
|
|
}
|
|
|
|
DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::DefinedOperator::IntrinsicOperator,
|
|
DefinedOperator::IntrinsicOperator,
|
|
// clang-format off
|
|
MS(Add, Add)
|
|
MS(AND, AND)
|
|
MS(Concat, Concat)
|
|
MS(Divide, Divide)
|
|
MS(EQ, EQ)
|
|
MS(EQV, EQV)
|
|
MS(GE, GE)
|
|
MS(GT, GT)
|
|
MS(NOT, NOT)
|
|
MS(LE, LE)
|
|
MS(LT, LT)
|
|
MS(Multiply, Multiply)
|
|
MS(NE, NE)
|
|
MS(NEQV, NEQV)
|
|
MS(OR, OR)
|
|
MS(Power, Power)
|
|
MS(Subtract, Subtract)
|
|
// clang-format on
|
|
);
|
|
|
|
return Fortran::common::visit(
|
|
common::visitors{
|
|
[&](const parser::DefinedOpName &s) {
|
|
return DefinedOperator{
|
|
DefinedOperator::DefinedOpName{makeObject(s.v, semaCtx)}};
|
|
},
|
|
[&](const parser::DefinedOperator::IntrinsicOperator &s) {
|
|
return DefinedOperator{convert(s)};
|
|
},
|
|
},
|
|
inp.u);
|
|
}
|
|
|
|
ProcedureDesignator
|
|
makeProcedureDesignator(const parser::ProcedureDesignator &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return ProcedureDesignator{Fortran::common::visit(
|
|
common::visitors{
|
|
[&](const parser::Name &t) { return makeObject(t, semaCtx); },
|
|
[&](const parser::ProcComponentRef &t) {
|
|
return makeObject(t.v.thing, semaCtx);
|
|
},
|
|
},
|
|
inp.u)};
|
|
}
|
|
|
|
ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Fortran::common::visit(
|
|
common::visitors{
|
|
[&](const parser::DefinedOperator &s) {
|
|
return ReductionOperator{makeDefinedOperator(s, semaCtx)};
|
|
},
|
|
[&](const parser::ProcedureDesignator &s) {
|
|
return ReductionOperator{makeProcedureDesignator(s, semaCtx)};
|
|
},
|
|
},
|
|
inp.u);
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// Actual clauses. Each T (where tomp::T exists in ClauseT) has its "make".
|
|
|
|
Absent make(const parser::OmpClause::Absent &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
llvm_unreachable("Unimplemented: absent");
|
|
}
|
|
|
|
// AcqRel: empty
|
|
// Acquire: empty
|
|
// AdjustArgs: incomplete
|
|
|
|
Affinity make(const parser::OmpClause::Affinity &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpAffinityClause
|
|
auto &t0 = std::get<std::optional<parser::OmpIteratorModifier>>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto &&maybeIter =
|
|
maybeApply([&](auto &&s) { return makeIterator(s, semaCtx); }, t0);
|
|
|
|
return Affinity{{/*Iterator=*/std::move(maybeIter),
|
|
/*LocatorList=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
Align make(const parser::OmpClause::Align &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: align");
|
|
}
|
|
|
|
Aligned make(const parser::OmpClause::Aligned &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpAlignedClause
|
|
auto &t0 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
auto &t1 = std::get<std::optional<parser::ScalarIntConstantExpr>>(inp.v.t);
|
|
|
|
return Aligned{{
|
|
/*Alignment=*/maybeApply(makeExprFn(semaCtx), t1),
|
|
/*List=*/makeObjects(t0, semaCtx),
|
|
}};
|
|
}
|
|
|
|
Allocate make(const parser::OmpClause::Allocate &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpAllocateClause
|
|
using wrapped = parser::OmpAllocateClause;
|
|
auto &t0 = std::get<std::optional<wrapped::AllocateModifier>>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
if (!t0) {
|
|
return Allocate{{/*AllocatorSimpleModifier=*/std::nullopt,
|
|
/*AllocatorComplexModifier=*/std::nullopt,
|
|
/*AlignModifier=*/std::nullopt,
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
using Tuple = decltype(Allocate::t);
|
|
|
|
return Allocate{Fortran::common::visit(
|
|
common::visitors{
|
|
// simple-modifier
|
|
[&](const wrapped::AllocateModifier::Allocator &v) -> Tuple {
|
|
return {/*AllocatorSimpleModifier=*/makeExpr(v.v, semaCtx),
|
|
/*AllocatorComplexModifier=*/std::nullopt,
|
|
/*AlignModifier=*/std::nullopt,
|
|
/*List=*/makeObjects(t1, semaCtx)};
|
|
},
|
|
// complex-modifier + align-modifier
|
|
[&](const wrapped::AllocateModifier::ComplexModifier &v) -> Tuple {
|
|
auto &s0 = std::get<wrapped::AllocateModifier::Allocator>(v.t);
|
|
auto &s1 = std::get<wrapped::AllocateModifier::Align>(v.t);
|
|
return {
|
|
/*AllocatorSimpleModifier=*/std::nullopt,
|
|
/*AllocatorComplexModifier=*/Allocator{makeExpr(s0.v, semaCtx)},
|
|
/*AlignModifier=*/Align{makeExpr(s1.v, semaCtx)},
|
|
/*List=*/makeObjects(t1, semaCtx)};
|
|
},
|
|
// align-modifier
|
|
[&](const wrapped::AllocateModifier::Align &v) -> Tuple {
|
|
return {/*AllocatorSimpleModifier=*/std::nullopt,
|
|
/*AllocatorComplexModifier=*/std::nullopt,
|
|
/*AlignModifier=*/Align{makeExpr(v.v, semaCtx)},
|
|
/*List=*/makeObjects(t1, semaCtx)};
|
|
},
|
|
},
|
|
t0->u)};
|
|
}
|
|
|
|
Allocator make(const parser::OmpClause::Allocator &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return Allocator{/*Allocator=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// AppendArgs: incomplete
|
|
|
|
At make(const parser::OmpClause::At &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: at");
|
|
}
|
|
|
|
// Never called, but needed for using "make" as a Clause visitor.
|
|
// See comment about "requires" clauses in Clauses.h.
|
|
AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpAtomicDefaultMemOrderClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, common::OmpAtomicDefaultMemOrderType,
|
|
AtomicDefaultMemOrder::MemoryOrder,
|
|
// clang-format off
|
|
MS(AcqRel, AcqRel)
|
|
MS(Relaxed, Relaxed)
|
|
MS(SeqCst, SeqCst)
|
|
// clang-format on
|
|
);
|
|
|
|
return AtomicDefaultMemOrder{/*MemoryOrder=*/convert(inp.v.v)};
|
|
}
|
|
|
|
Bind make(const parser::OmpClause::Bind &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: bind");
|
|
}
|
|
|
|
// CancellationConstructType: empty
|
|
// Capture: empty
|
|
|
|
Collapse make(const parser::OmpClause::Collapse &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntConstantExpr
|
|
return Collapse{/*N=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Compare: empty
|
|
|
|
Contains make(const parser::OmpClause::Contains &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
llvm_unreachable("Unimplemented: contains");
|
|
}
|
|
|
|
Copyin make(const parser::OmpClause::Copyin &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Copyin{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
Copyprivate make(const parser::OmpClause::Copyprivate &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Copyprivate{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
Default make(const parser::OmpClause::Default &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDefaultClause
|
|
using wrapped = parser::OmpDefaultClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::Type, Default::DataSharingAttribute,
|
|
// clang-format off
|
|
MS(Firstprivate, Firstprivate)
|
|
MS(None, None)
|
|
MS(Private, Private)
|
|
MS(Shared, Shared)
|
|
// clang-format on
|
|
);
|
|
|
|
return Default{/*DataSharingAttribute=*/convert(inp.v.v)};
|
|
}
|
|
|
|
Defaultmap make(const parser::OmpClause::Defaultmap &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDefaultmapClause
|
|
using wrapped = parser::OmpDefaultmapClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, wrapped::ImplicitBehavior, Defaultmap::ImplicitBehavior,
|
|
// clang-format off
|
|
MS(Alloc, Alloc)
|
|
MS(To, To)
|
|
MS(From, From)
|
|
MS(Tofrom, Tofrom)
|
|
MS(Firstprivate, Firstprivate)
|
|
MS(None, None)
|
|
MS(Default, Default)
|
|
// MS(, Present) missing-in-parser
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, wrapped::VariableCategory, Defaultmap::VariableCategory,
|
|
// clang-format off
|
|
MS(Scalar, Scalar)
|
|
MS(Aggregate, Aggregate)
|
|
MS(Pointer, Pointer)
|
|
MS(Allocatable, Allocatable)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t);
|
|
auto &t1 = std::get<std::optional<wrapped::VariableCategory>>(inp.v.t);
|
|
return Defaultmap{{/*ImplicitBehavior=*/convert1(t0),
|
|
/*VariableCategory=*/maybeApply(convert2, t1)}};
|
|
}
|
|
|
|
Depend make(const parser::OmpClause::Depend &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDependClause
|
|
using wrapped = parser::OmpDependClause;
|
|
using Variant = decltype(Depend::u);
|
|
// Iteration is the equivalent of parser::OmpDependSinkVec
|
|
using Iteration = Doacross::Vector::value_type; // LoopIterationT
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, parser::OmpDependenceType::Type, Depend::TaskDependenceType,
|
|
// clang-format off
|
|
MS(In, In)
|
|
MS(Out, Out)
|
|
MS(Inout, Inout)
|
|
// MS(, Mutexinoutset) // missing-in-parser
|
|
// MS(, Inputset) // missing-in-parser
|
|
// MS(, Depobj) // missing-in-parser
|
|
// clang-format on
|
|
);
|
|
|
|
return Depend{Fortran::common::visit( //
|
|
common::visitors{
|
|
// Doacross
|
|
[&](const wrapped::Source &s) -> Variant {
|
|
return Doacross{
|
|
{/*DependenceType=*/Doacross::DependenceType::Source,
|
|
/*Vector=*/{}}};
|
|
},
|
|
// Doacross
|
|
[&](const wrapped::Sink &s) -> Variant {
|
|
using DependLength = parser::OmpDependSinkVecLength;
|
|
auto convert2 = [&](const parser::OmpDependSinkVec &v) {
|
|
auto &t0 = std::get<parser::Name>(v.t);
|
|
auto &t1 = std::get<std::optional<DependLength>>(v.t);
|
|
|
|
auto convert3 = [&](const DependLength &u) {
|
|
auto &s0 = std::get<parser::DefinedOperator>(u.t);
|
|
auto &s1 = std::get<parser::ScalarIntConstantExpr>(u.t);
|
|
return Iteration::Distance{
|
|
{makeDefinedOperator(s0, semaCtx), makeExpr(s1, semaCtx)}};
|
|
};
|
|
return Iteration{
|
|
{makeObject(t0, semaCtx), maybeApply(convert3, t1)}};
|
|
};
|
|
return Doacross{{/*DependenceType=*/Doacross::DependenceType::Sink,
|
|
/*Vector=*/makeList(s.v, convert2)}};
|
|
},
|
|
// Depend::WithLocators
|
|
[&](const wrapped::InOut &s) -> Variant {
|
|
auto &t0 = std::get<parser::OmpDependenceType>(s.t);
|
|
auto &t1 = std::get<std::list<parser::Designator>>(s.t);
|
|
auto convert4 = [&](const parser::Designator &t) {
|
|
return makeObject(t, semaCtx);
|
|
};
|
|
return Depend::WithLocators{
|
|
{/*TaskDependenceType=*/convert1(t0.v),
|
|
/*Iterator=*/std::nullopt,
|
|
/*LocatorList=*/makeList(t1, convert4)}};
|
|
},
|
|
},
|
|
inp.v.u)};
|
|
}
|
|
|
|
// Depobj: empty
|
|
|
|
Destroy make(const parser::OmpClause::Destroy &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: destroy");
|
|
}
|
|
|
|
Detach make(const parser::OmpClause::Detach &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: detach");
|
|
}
|
|
|
|
Device make(const parser::OmpClause::Device &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDeviceClause
|
|
using wrapped = parser::OmpDeviceClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpDeviceClause::DeviceModifier, Device::DeviceModifier,
|
|
// clang-format off
|
|
MS(Ancestor, Ancestor)
|
|
MS(Device_Num, DeviceNum)
|
|
// clang-format on
|
|
);
|
|
auto &t0 = std::get<std::optional<wrapped::DeviceModifier>>(inp.v.t);
|
|
auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);
|
|
return Device{{/*DeviceModifier=*/maybeApply(convert, t0),
|
|
/*DeviceDescription=*/makeExpr(t1, semaCtx)}};
|
|
}
|
|
|
|
DeviceType make(const parser::OmpClause::DeviceType &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDeviceTypeClause
|
|
using wrapped = parser::OmpDeviceTypeClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::Type, DeviceType::DeviceTypeDescription,
|
|
// clang-format off
|
|
MS(Any, Any)
|
|
MS(Host, Host)
|
|
MS(Nohost, Nohost)
|
|
// clang-format om
|
|
);
|
|
return DeviceType{/*DeviceTypeDescription=*/convert(inp.v.v)};
|
|
}
|
|
|
|
DistSchedule make(const parser::OmpClause::DistSchedule &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::optional<parser::ScalarIntExpr>
|
|
return DistSchedule{{/*Kind=*/DistSchedule::Kind::Static,
|
|
/*ChunkSize=*/maybeApply(makeExprFn(semaCtx), inp.v)}};
|
|
}
|
|
|
|
Doacross make(const parser::OmpClause::Doacross &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: doacross");
|
|
}
|
|
|
|
// DynamicAllocators: empty
|
|
|
|
Enter make(const parser::OmpClause::Enter &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Enter{makeObjects(/*List=*/inp.v, semaCtx)};
|
|
}
|
|
|
|
Exclusive make(const parser::OmpClause::Exclusive &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: exclusive");
|
|
}
|
|
|
|
Fail make(const parser::OmpClause::Fail &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: fail");
|
|
}
|
|
|
|
Filter make(const parser::OmpClause::Filter &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return Filter{/*ThreadNum=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Final make(const parser::OmpClause::Final &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarLogicalExpr
|
|
return Final{/*Finalize=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Firstprivate make(const parser::OmpClause::Firstprivate &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Firstprivate{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Flush: empty
|
|
|
|
From make(const parser::OmpClause::From &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return From{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
|
|
/*Iterator=*/std::nullopt,
|
|
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
|
|
}
|
|
|
|
// Full: empty
|
|
|
|
Grainsize make(const parser::OmpClause::Grainsize &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return Grainsize{{/*Prescriptiveness=*/std::nullopt,
|
|
/*GrainSize=*/makeExpr(inp.v, semaCtx)}};
|
|
}
|
|
|
|
HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return HasDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
Hint make(const parser::OmpClause::Hint &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ConstantExpr
|
|
return Hint{/*HintExpr=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Holds make(const parser::OmpClause::Holds &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
llvm_unreachable("Unimplemented: holds");
|
|
}
|
|
|
|
If make(const parser::OmpClause::If &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpIfClause
|
|
using wrapped = parser::OmpIfClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::DirectiveNameModifier, llvm::omp::Directive,
|
|
// clang-format off
|
|
MS(Parallel, OMPD_parallel)
|
|
MS(Simd, OMPD_simd)
|
|
MS(Target, OMPD_target)
|
|
MS(TargetData, OMPD_target_data)
|
|
MS(TargetEnterData, OMPD_target_enter_data)
|
|
MS(TargetExitData, OMPD_target_exit_data)
|
|
MS(TargetUpdate, OMPD_target_update)
|
|
MS(Task, OMPD_task)
|
|
MS(Taskloop, OMPD_taskloop)
|
|
MS(Teams, OMPD_teams)
|
|
// clang-format on
|
|
);
|
|
auto &t0 = std::get<std::optional<wrapped::DirectiveNameModifier>>(inp.v.t);
|
|
auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t);
|
|
return If{{/*DirectiveNameModifier=*/maybeApply(convert, t0),
|
|
/*IfExpression=*/makeExpr(t1, semaCtx)}};
|
|
}
|
|
|
|
// Inbranch: empty
|
|
|
|
Inclusive make(const parser::OmpClause::Inclusive &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: inclusive");
|
|
}
|
|
|
|
Indirect make(const parser::OmpClause::Indirect &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: indirect");
|
|
}
|
|
|
|
Init make(const parser::OmpClause::Init &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: init");
|
|
}
|
|
|
|
// Initializer: missing-in-parser
|
|
|
|
InReduction make(const parser::OmpClause::InReduction &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpInReductionClause
|
|
auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
return InReduction{
|
|
{/*ReductionIdentifiers=*/{makeReductionOperator(t0, semaCtx)},
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return IsDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
Lastprivate make(const parser::OmpClause::Lastprivate &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpLastprivateClause
|
|
using wrapped = parser::OmpLastprivateClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpLastprivateClause::LastprivateModifier,
|
|
Lastprivate::LastprivateModifier,
|
|
// clang-format off
|
|
MS(Conditional, Conditional)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 = std::get<std::optional<wrapped::LastprivateModifier>>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
return Lastprivate{{/*LastprivateModifier=*/maybeApply(convert, t0),
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
Linear make(const parser::OmpClause::Linear &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpLinearClause
|
|
using wrapped = parser::OmpLinearClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpLinearModifier::Type, Linear::LinearModifier,
|
|
// clang-format off
|
|
MS(Ref, Ref)
|
|
MS(Val, Val)
|
|
MS(Uval, Uval)
|
|
// clang-format on
|
|
);
|
|
|
|
using Tuple = decltype(Linear::t);
|
|
|
|
return Linear{Fortran::common::visit(
|
|
common::visitors{
|
|
[&](const wrapped::WithModifier &s) -> Tuple {
|
|
return {
|
|
/*StepSimpleModifier=*/std::nullopt,
|
|
/*StepComplexModifier=*/maybeApply(makeExprFn(semaCtx), s.step),
|
|
/*LinearModifier=*/convert(s.modifier.v),
|
|
/*List=*/makeList(s.names, makeObjectFn(semaCtx))};
|
|
},
|
|
[&](const wrapped::WithoutModifier &s) -> Tuple {
|
|
return {
|
|
/*StepSimpleModifier=*/maybeApply(makeExprFn(semaCtx), s.step),
|
|
/*StepComplexModifier=*/std::nullopt,
|
|
/*LinearModifier=*/std::nullopt,
|
|
/*List=*/makeList(s.names, makeObjectFn(semaCtx))};
|
|
},
|
|
},
|
|
inp.v.u)};
|
|
}
|
|
|
|
Link make(const parser::OmpClause::Link &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Link{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
Map make(const parser::OmpClause::Map &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpMapClause
|
|
using wrapped = parser::OmpMapClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, parser::OmpMapClause::Type, Map::MapType,
|
|
// clang-format off
|
|
MS(Alloc, Alloc)
|
|
MS(Delete, Delete)
|
|
MS(From, From)
|
|
MS(Release, Release)
|
|
MS(To, To)
|
|
MS(Tofrom, Tofrom)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, parser::OmpMapClause::TypeModifier, Map::MapTypeModifier,
|
|
// clang-format off
|
|
MS(Always, Always)
|
|
MS(Close, Close)
|
|
MS(Ompx_Hold, OmpxHold)
|
|
MS(Present, Present)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 = std::get<std::optional<std::list<wrapped::TypeModifier>>>(inp.v.t);
|
|
auto &t1 =
|
|
std::get<std::optional<std::list<parser::OmpIteratorModifier>>>(inp.v.t);
|
|
auto &t2 = std::get<std::optional<std::list<wrapped::Type>>>(inp.v.t);
|
|
auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
// These should have been diagnosed already.
|
|
assert((!t1 || t1->size() == 1) && "Only one iterator modifier is allowed");
|
|
assert((!t2 || t2->size() == 1) && "Only one map type is allowed");
|
|
|
|
auto iterator = [&]() -> std::optional<Iterator> {
|
|
if (t1)
|
|
return makeIterator(t1->front(), semaCtx);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
std::optional<Map::MapType> maybeType;
|
|
if (t2)
|
|
maybeType = maybeApply(convert1, std::optional<wrapped::Type>(t2->front()));
|
|
|
|
std::optional<Map::MapTypeModifiers> maybeTypeMods = maybeApply(
|
|
[&](const std::list<wrapped::TypeModifier> &typeMods) {
|
|
Map::MapTypeModifiers mods;
|
|
for (wrapped::TypeModifier mod : typeMods)
|
|
mods.push_back(convert2(mod));
|
|
return mods;
|
|
},
|
|
t0);
|
|
|
|
return Map{{/*MapType=*/maybeType,
|
|
/*MapTypeModifiers=*/maybeTypeMods,
|
|
/*Mapper=*/std::nullopt, /*Iterator=*/std::move(iterator),
|
|
/*LocatorList=*/makeObjects(t3, semaCtx)}};
|
|
}
|
|
|
|
// Match: incomplete
|
|
// MemoryOrder: empty
|
|
// Mergeable: empty
|
|
|
|
Message make(const parser::OmpClause::Message &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: message");
|
|
}
|
|
|
|
Nocontext make(const parser::OmpClause::Nocontext &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarLogicalExpr
|
|
return Nocontext{/*DoNotUpdateContext=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Nogroup: empty
|
|
|
|
Nontemporal make(const parser::OmpClause::Nontemporal &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::list<parser::Name>
|
|
return Nontemporal{/*List=*/makeList(inp.v, makeObjectFn(semaCtx))};
|
|
}
|
|
|
|
// NoOpenmp: empty
|
|
// NoOpenmpRoutines: empty
|
|
// NoParallelism: empty
|
|
// Notinbranch: empty
|
|
|
|
Novariants make(const parser::OmpClause::Novariants &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarLogicalExpr
|
|
return Novariants{/*DoNotUseVariant=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Nowait: empty
|
|
|
|
NumTasks make(const parser::OmpClause::NumTasks &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return NumTasks{{/*Prescriptiveness=*/std::nullopt,
|
|
/*NumTasks=*/makeExpr(inp.v, semaCtx)}};
|
|
}
|
|
|
|
NumTeams make(const parser::OmpClause::NumTeams &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
List<NumTeams::Range> v{{{/*LowerBound=*/std::nullopt,
|
|
/*UpperBound=*/makeExpr(inp.v, semaCtx)}}};
|
|
return NumTeams{/*List=*/v};
|
|
}
|
|
|
|
NumThreads make(const parser::OmpClause::NumThreads &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return NumThreads{/*Nthreads=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// OmpxAttribute: empty
|
|
// OmpxBare: empty
|
|
|
|
OmpxDynCgroupMem make(const parser::OmpClause::OmpxDynCgroupMem &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return OmpxDynCgroupMem{makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Order make(const parser::OmpClause::Order &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpOrderClause
|
|
using wrapped = parser::OmpOrderClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, parser::OmpOrderModifier::Kind, Order::OrderModifier,
|
|
// clang-format off
|
|
MS(Reproducible, Reproducible)
|
|
MS(Unconstrained, Unconstrained)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, wrapped::Type, Order::Ordering,
|
|
// clang-format off
|
|
MS(Concurrent, Concurrent)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 = std::get<std::optional<parser::OmpOrderModifier>>(inp.v.t);
|
|
auto &t1 = std::get<wrapped::Type>(inp.v.t);
|
|
|
|
auto convert3 = [&](const parser::OmpOrderModifier &s) {
|
|
return Fortran::common::visit(
|
|
[&](parser::OmpOrderModifier::Kind k) { return convert1(k); }, s.u);
|
|
};
|
|
return Order{
|
|
{/*OrderModifier=*/maybeApply(convert3, t0), /*Ordering=*/convert2(t1)}};
|
|
}
|
|
|
|
Ordered make(const parser::OmpClause::Ordered &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::optional<parser::ScalarIntConstantExpr>
|
|
return Ordered{/*N=*/maybeApply(makeExprFn(semaCtx), inp.v)};
|
|
}
|
|
|
|
// Otherwise: incomplete, missing-in-parser
|
|
|
|
Partial make(const parser::OmpClause::Partial &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::optional<parser::ScalarIntConstantExpr>
|
|
return Partial{/*UnrollFactor=*/maybeApply(makeExprFn(semaCtx), inp.v)};
|
|
}
|
|
|
|
Priority make(const parser::OmpClause::Priority &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return Priority{/*PriorityValue=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Private make(const parser::OmpClause::Private &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Private{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
ProcBind make(const parser::OmpClause::ProcBind &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpProcBindClause
|
|
using wrapped = parser::OmpProcBindClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::Type, ProcBind::AffinityPolicy,
|
|
// clang-format off
|
|
MS(Close, Close)
|
|
MS(Master, Master)
|
|
MS(Spread, Spread)
|
|
MS(Primary, Primary)
|
|
// clang-format on
|
|
);
|
|
return ProcBind{/*AffinityPolicy=*/convert(inp.v.v)};
|
|
}
|
|
|
|
// Read: empty
|
|
|
|
Reduction make(const parser::OmpClause::Reduction &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpReductionClause
|
|
using wrapped = parser::OmpReductionClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::ReductionModifier, Reduction::ReductionModifier,
|
|
// clang-format off
|
|
MS(Inscan, Inscan)
|
|
MS(Task, Task)
|
|
MS(Default, Default)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 =
|
|
std::get<std::optional<parser::OmpReductionClause::ReductionModifier>>(
|
|
inp.v.t);
|
|
auto &t1 = std::get<parser::OmpReductionOperator>(inp.v.t);
|
|
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
return Reduction{
|
|
{/*ReductionModifier=*/t0
|
|
? std::make_optional<Reduction::ReductionModifier>(convert(*t0))
|
|
: std::nullopt,
|
|
/*ReductionIdentifiers=*/{makeReductionOperator(t1, semaCtx)},
|
|
/*List=*/makeObjects(t2, semaCtx)}};
|
|
}
|
|
|
|
// Relaxed: empty
|
|
// Release: empty
|
|
// ReverseOffload: empty
|
|
|
|
Safelen make(const parser::OmpClause::Safelen &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntConstantExpr
|
|
return Safelen{/*Length=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Schedule make(const parser::OmpClause::Schedule &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpScheduleClause
|
|
using wrapped = parser::OmpScheduleClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, wrapped::ScheduleType, Schedule::Kind,
|
|
// clang-format off
|
|
MS(Static, Static)
|
|
MS(Dynamic, Dynamic)
|
|
MS(Guided, Guided)
|
|
MS(Auto, Auto)
|
|
MS(Runtime, Runtime)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, parser::OmpScheduleModifierType::ModType,
|
|
Schedule::OrderingModifier,
|
|
// clang-format off
|
|
MS(Monotonic, Monotonic)
|
|
MS(Nonmonotonic, Nonmonotonic)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert3, parser::OmpScheduleModifierType::ModType,
|
|
Schedule::ChunkModifier,
|
|
// clang-format off
|
|
MS(Simd, Simd)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &t0 = std::get<std::optional<parser::OmpScheduleModifier>>(inp.v.t);
|
|
auto &t1 = std::get<wrapped::ScheduleType>(inp.v.t);
|
|
auto &t2 = std::get<std::optional<parser::ScalarIntExpr>>(inp.v.t);
|
|
|
|
if (!t0) {
|
|
return Schedule{{/*Kind=*/convert1(t1), /*OrderingModifier=*/std::nullopt,
|
|
/*ChunkModifier=*/std::nullopt,
|
|
/*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t2)}};
|
|
}
|
|
|
|
// The members of parser::OmpScheduleModifier correspond to OrderingModifier,
|
|
// and ChunkModifier, but they can appear in any order.
|
|
auto &m1 = std::get<parser::OmpScheduleModifier::Modifier1>(t0->t);
|
|
auto &m2 =
|
|
std::get<std::optional<parser::OmpScheduleModifier::Modifier2>>(t0->t);
|
|
|
|
std::optional<Schedule::OrderingModifier> omod;
|
|
std::optional<Schedule::ChunkModifier> cmod;
|
|
|
|
if (m1.v.v == parser::OmpScheduleModifierType::ModType::Simd) {
|
|
// m1 is chunk-modifier
|
|
cmod = convert3(m1.v.v);
|
|
if (m2)
|
|
omod = convert2(m2->v.v);
|
|
} else {
|
|
// m1 is ordering-modifier
|
|
omod = convert2(m1.v.v);
|
|
if (m2)
|
|
cmod = convert3(m2->v.v);
|
|
}
|
|
|
|
return Schedule{{/*Kind=*/convert1(t1),
|
|
/*OrderingModifier=*/omod,
|
|
/*ChunkModifier=*/cmod,
|
|
/*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t2)}};
|
|
}
|
|
|
|
// SeqCst: empty
|
|
|
|
Severity make(const parser::OmpClause::Severity &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: severity");
|
|
}
|
|
|
|
Shared make(const parser::OmpClause::Shared &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Shared{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Simd: empty
|
|
|
|
Simdlen make(const parser::OmpClause::Simdlen &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntConstantExpr
|
|
return Simdlen{/*Length=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
Sizes make(const parser::OmpClause::Sizes &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::list<parser::ScalarIntExpr>
|
|
return Sizes{/*SizeList=*/makeList(inp.v, makeExprFn(semaCtx))};
|
|
}
|
|
|
|
Permutation make(const parser::OmpClause::Permutation &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::list<parser::ScalarIntConstantExpr>
|
|
return Permutation{/*ArgList=*/makeList(inp.v, makeExprFn(semaCtx))};
|
|
}
|
|
|
|
TaskReduction make(const parser::OmpClause::TaskReduction &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpReductionClause
|
|
auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
return TaskReduction{
|
|
{/*ReductionIdentifiers=*/{makeReductionOperator(t0, semaCtx)},
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::ScalarIntExpr
|
|
return ThreadLimit{/*Threadlim=*/makeExpr(inp.v, semaCtx)};
|
|
}
|
|
|
|
// Threadprivate: empty
|
|
// Threads: empty
|
|
|
|
To make(const parser::OmpClause::To &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return To{{/*Expectation=*/std::nullopt, /*Mapper=*/std::nullopt,
|
|
/*Iterator=*/std::nullopt,
|
|
/*LocatorList=*/makeObjects(inp.v, semaCtx)}};
|
|
}
|
|
|
|
// UnifiedAddress: empty
|
|
// UnifiedSharedMemory: empty
|
|
|
|
Uniform make(const parser::OmpClause::Uniform &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::list<parser::Name>
|
|
return Uniform{/*ParameterList=*/makeList(inp.v, makeObjectFn(semaCtx))};
|
|
}
|
|
|
|
// Unknown: empty
|
|
// Untied: empty
|
|
|
|
Update make(const parser::OmpClause::Update &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
return Update{/*TaskDependenceType=*/std::nullopt};
|
|
}
|
|
|
|
Use make(const parser::OmpClause::Use &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: use");
|
|
}
|
|
|
|
UseDeviceAddr make(const parser::OmpClause::UseDeviceAddr &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return UseDeviceAddr{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
UseDevicePtr make(const parser::OmpClause::UseDevicePtr &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return UseDevicePtr{/*List=*/makeObjects(inp.v, semaCtx)};
|
|
}
|
|
|
|
UsesAllocators make(const parser::OmpClause::UsesAllocators &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: uses_allocators");
|
|
}
|
|
|
|
// Weak: empty
|
|
// When: incomplete
|
|
// Write: empty
|
|
} // namespace clause
|
|
|
|
Clause makeClause(const parser::OmpClause &cls,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Fortran::common::visit(
|
|
[&](auto &&s) {
|
|
return makeClause(cls.Id(), clause::make(s, semaCtx), cls.source);
|
|
},
|
|
cls.u);
|
|
}
|
|
|
|
List<Clause> makeClauses(const parser::OmpClauseList &clauses,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return makeList(clauses.v, [&](const parser::OmpClause &s) {
|
|
return makeClause(s, semaCtx);
|
|
});
|
|
}
|
|
|
|
bool transferLocations(const List<Clause> &from, List<Clause> &to) {
|
|
bool allDone = true;
|
|
|
|
for (Clause &clause : to) {
|
|
if (!clause.source.empty())
|
|
continue;
|
|
auto found =
|
|
llvm::find_if(from, [&](const Clause &c) { return c.id == clause.id; });
|
|
// This is not completely accurate, but should be good enough for now.
|
|
// It can be improved in the future if necessary, but in cases of
|
|
// synthesized clauses getting accurate location may be impossible.
|
|
if (found != from.end()) {
|
|
clause.source = found->source;
|
|
} else {
|
|
// Found a clause that won't have "source".
|
|
allDone = false;
|
|
}
|
|
}
|
|
|
|
return allDone;
|
|
}
|
|
|
|
} // namespace Fortran::lower::omp
|