
Add parser support for the new AUTOMAP modifier for OpenMP Declare Target Enter clause introduced in OpenMP 6.0 section 7.9.7.
1542 lines
52 KiB
C++
1542 lines
52 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 "flang/Lower/OpenMP/Clauses.h"
|
|
|
|
#include "flang/Common/idioms.h"
|
|
#include "flang/Evaluate/expression.h"
|
|
#include "flang/Optimizer/Builder/Todo.h"
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "flang/Semantics/expression.h"
|
|
#include "flang/Semantics/openmp-modifiers.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);
|
|
const std::optional<evaluate::Expr<evaluate::SomeType>> &maybeDsg =
|
|
std::get<1>(sd);
|
|
if (!maybeDsg)
|
|
return; // Symbol with no designator -> OK
|
|
assert(symbol && "Expecting symbol");
|
|
std::optional<evaluate::DataRef> maybeRef = evaluate::ExtractDataRef(
|
|
*maybeDsg, /*intoSubstring=*/true, /*intoComplexPart=*/true);
|
|
if (maybeRef) {
|
|
if (&maybeRef->GetLastSymbol() == symbol)
|
|
return; // Symbol with a designator for it -> OK
|
|
llvm_unreachable("Expecting designator for given symbol");
|
|
} else {
|
|
#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);
|
|
}
|
|
|
|
ObjectList makeObjects(const parser::OmpArgumentList &objects,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return makeList(objects.v, [&](const parser::OmpArgument &arg) {
|
|
return common::visit(
|
|
common::visitors{
|
|
[&](const parser::OmpLocator &locator) -> Object {
|
|
if (auto *object = std::get_if<parser::OmpObject>(&locator.u)) {
|
|
return makeObject(*object, semaCtx);
|
|
}
|
|
llvm_unreachable("Expecting object");
|
|
},
|
|
[](auto &&s) -> Object { //
|
|
llvm_unreachable("Expecting object");
|
|
},
|
|
},
|
|
arg.u);
|
|
});
|
|
}
|
|
|
|
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 (auto *symRef = base.UnwrapSymbolRef()) {
|
|
// This is the base symbol of the array reference, which is the same
|
|
// as the symbol in the input object,
|
|
// e.g. A(i) is represented as {Symbol(A), Designator(ArrayRef(A, i))}.
|
|
// Here we have the Symbol(A), which is what we started with.
|
|
(void)symRef;
|
|
assert(&**symRef == object.sym());
|
|
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(NoOpenmpConstructs, NoOpenmpConstructs);
|
|
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(SelfMaps, SelfMaps);
|
|
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(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);
|
|
|
|
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::OmpIterator &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::OmpReductionIdentifier &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);
|
|
}
|
|
|
|
clause::DependenceType makeDepType(const parser::OmpDependenceType &inp) {
|
|
switch (inp.v) {
|
|
case parser::OmpDependenceType::Value::Sink:
|
|
return clause::DependenceType::Sink;
|
|
case parser::OmpDependenceType::Value::Source:
|
|
return clause::DependenceType::Source;
|
|
}
|
|
llvm_unreachable("Unexpected dependence type");
|
|
}
|
|
|
|
clause::DependenceType makeDepType(const parser::OmpTaskDependenceType &inp) {
|
|
switch (inp.v) {
|
|
case parser::OmpTaskDependenceType::Value::Depobj:
|
|
return clause::DependenceType::Depobj;
|
|
case parser::OmpTaskDependenceType::Value::In:
|
|
return clause::DependenceType::In;
|
|
case parser::OmpTaskDependenceType::Value::Inout:
|
|
return clause::DependenceType::Inout;
|
|
case parser::OmpTaskDependenceType::Value::Inoutset:
|
|
return clause::DependenceType::Inoutset;
|
|
case parser::OmpTaskDependenceType::Value::Mutexinoutset:
|
|
return clause::DependenceType::Mutexinoutset;
|
|
case parser::OmpTaskDependenceType::Value::Out:
|
|
return clause::DependenceType::Out;
|
|
}
|
|
llvm_unreachable("Unexpected task dependence type");
|
|
}
|
|
|
|
clause::Prescriptiveness
|
|
makePrescriptiveness(parser::OmpPrescriptiveness::Value v) {
|
|
switch (v) {
|
|
case parser::OmpPrescriptiveness::Value::Strict:
|
|
return clause::Prescriptiveness::Strict;
|
|
}
|
|
llvm_unreachable("Unexpected prescriptiveness");
|
|
}
|
|
|
|
// --------------------------------------------------------------------
|
|
// 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 &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto &&maybeIter =
|
|
m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};
|
|
|
|
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 &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto &t0 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
auto *m1 = semantics::OmpGetUniqueModifier<parser::OmpAlignment>(mods);
|
|
|
|
return Aligned{{
|
|
/*Alignment=*/maybeApplyToV(makeExprFn(semaCtx), m1),
|
|
/*List=*/makeObjects(t0, semaCtx),
|
|
}};
|
|
}
|
|
|
|
Allocate make(const parser::OmpClause::Allocate &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpAllocateClause
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpAlignModifier>(mods);
|
|
auto *m1 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpAllocatorComplexModifier>(
|
|
mods);
|
|
auto *m2 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpAllocatorSimpleModifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto makeAllocator = [&](auto *mod) -> std::optional<Allocator> {
|
|
if (mod)
|
|
return Allocator{makeExpr(mod->v, semaCtx)};
|
|
return std::nullopt;
|
|
};
|
|
|
|
auto makeAlign = [&](const parser::ScalarIntExpr &expr) {
|
|
return Align{makeExpr(expr, semaCtx)};
|
|
};
|
|
|
|
auto maybeAllocator = m1 ? makeAllocator(m1) : makeAllocator(m2);
|
|
return Allocate{{/*AllocatorComplexModifier=*/std::move(maybeAllocator),
|
|
/*AlignModifier=*/maybeApplyToV(makeAlign, m0),
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
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::OmpMemoryOrderType, AtomicDefaultMemOrder::MemoryOrder,
|
|
// clang-format off
|
|
MS(Acq_Rel, AcqRel)
|
|
MS(Acquire, Acquire)
|
|
MS(Relaxed, Relaxed)
|
|
MS(Release, Release)
|
|
MS(Seq_Cst, SeqCst)
|
|
// clang-format on
|
|
);
|
|
|
|
return AtomicDefaultMemOrder{/*MemoryOrder=*/convert(inp.v.v)};
|
|
}
|
|
|
|
Bind make(const parser::OmpClause::Bind &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpBindClause
|
|
using wrapped = parser::OmpBindClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::Binding, Bind::Binding,
|
|
// clang-format off
|
|
MS(Teams, Teams)
|
|
MS(Parallel, Parallel)
|
|
MS(Thread, Thread)
|
|
// clang-format on
|
|
);
|
|
|
|
return Bind{/*Binding=*/convert(inp.v.v)};
|
|
}
|
|
|
|
CancellationConstructType
|
|
make(const parser::OmpClause::CancellationConstructType &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
auto name = std::get<parser::OmpDirectiveName>(inp.v.t);
|
|
CLAUSET_ENUM_CONVERT(
|
|
convert, llvm::omp::Directive, llvm::omp::CancellationConstructType,
|
|
// clang-format off
|
|
MS(OMPD_parallel, OMP_CANCELLATION_CONSTRUCT_Parallel)
|
|
MS(OMPD_do, OMP_CANCELLATION_CONSTRUCT_Loop)
|
|
MS(OMPD_sections, OMP_CANCELLATION_CONSTRUCT_Sections)
|
|
MS(OMPD_taskgroup, OMP_CANCELLATION_CONSTRUCT_Taskgroup)
|
|
// clang-format on
|
|
);
|
|
|
|
return CancellationConstructType{convert(name.v)};
|
|
}
|
|
|
|
// 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)};
|
|
}
|
|
|
|
// The Default clause is overloaded in OpenMP 5.0 and 5.1: it can be either
|
|
// a data-sharing clause, or a METADIRECTIVE clause. In the latter case, it
|
|
// has been superseded by the OTHERWISE clause.
|
|
// Disambiguate this in this representation: for the DSA case, create Default,
|
|
// and in the other case create Otherwise.
|
|
Default makeDefault(const parser::OmpClause::Default &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDefaultClause
|
|
using wrapped = parser::OmpDefaultClause;
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, wrapped::DataSharingAttribute, Default::DataSharingAttribute,
|
|
// clang-format off
|
|
MS(Firstprivate, Firstprivate)
|
|
MS(None, None)
|
|
MS(Private, Private)
|
|
MS(Shared, Shared)
|
|
// clang-format on
|
|
);
|
|
|
|
auto dsa = std::get<wrapped::DataSharingAttribute>(inp.v.u);
|
|
return Default{/*DataSharingAttribute=*/convert(dsa)};
|
|
}
|
|
|
|
Otherwise makeOtherwise(const parser::OmpClause::Default &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Otherwise{};
|
|
}
|
|
|
|
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, Present)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, parser::OmpVariableCategory::Value,
|
|
Defaultmap::VariableCategory,
|
|
// clang-format off
|
|
MS(Aggregate, Aggregate)
|
|
MS(All, All)
|
|
MS(Allocatable, Allocatable)
|
|
MS(Pointer, Pointer)
|
|
MS(Scalar, Scalar)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t);
|
|
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpVariableCategory>(mods);
|
|
|
|
auto category = t1 ? convert2(t1->v) : Defaultmap::VariableCategory::All;
|
|
return Defaultmap{{/*ImplicitBehavior=*/convert1(t0),
|
|
/*VariableCategory=*/category}};
|
|
}
|
|
|
|
Doacross makeDoacross(const parser::OmpDoacross &doa,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// Iteration is the equivalent of parser::OmpIteration
|
|
using Iteration = Doacross::Vector::value_type; // LoopIterationT
|
|
|
|
auto visitSource = [&](const parser::OmpDoacross::Source &) {
|
|
return Doacross{{/*DependenceType=*/Doacross::DependenceType::Source,
|
|
/*Vector=*/{}}};
|
|
};
|
|
|
|
auto visitSink = [&](const parser::OmpDoacross::Sink &s) {
|
|
using IterOffset = parser::OmpIterationOffset;
|
|
auto convert2 = [&](const parser::OmpIteration &v) {
|
|
auto &t0 = std::get<parser::Name>(v.t);
|
|
auto &t1 = std::get<std::optional<IterOffset>>(v.t);
|
|
|
|
auto convert3 = [&](const IterOffset &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.v, convert2)}};
|
|
};
|
|
|
|
return common::visit(common::visitors{visitSink, visitSource}, doa.u);
|
|
}
|
|
|
|
Depend make(const parser::OmpClause::Depend &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDependClause
|
|
using wrapped = parser::OmpDependClause;
|
|
using Variant = decltype(Depend::u);
|
|
|
|
auto visitTaskDep = [&](const wrapped::TaskDep &s) -> Variant {
|
|
auto &mods = semantics::OmpGetModifiers(s);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
|
|
auto *m1 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpTaskDependenceType>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(s.t);
|
|
assert(m1 && "expecting task dependence type");
|
|
|
|
auto &&maybeIter =
|
|
m0 ? makeIterator(*m0, semaCtx) : std::optional<Iterator>{};
|
|
return Depend::TaskDep{{/*DependenceType=*/makeDepType(*m1),
|
|
/*Iterator=*/std::move(maybeIter),
|
|
/*LocatorList=*/makeObjects(t1, semaCtx)}};
|
|
};
|
|
|
|
return Depend{common::visit( //
|
|
common::visitors{
|
|
// Doacross
|
|
[&](const parser::OmpDoacross &s) -> Variant {
|
|
return makeDoacross(s, semaCtx);
|
|
},
|
|
// Depend::TaskDep
|
|
visitTaskDep,
|
|
},
|
|
inp.v.u)};
|
|
}
|
|
|
|
// Depobj: empty
|
|
|
|
Destroy make(const parser::OmpClause::Destroy &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> std::optional<OmpDestroyClause>
|
|
auto &&maybeObject = maybeApply(
|
|
[&](const parser::OmpDestroyClause &c) {
|
|
return makeObject(c.v, semaCtx);
|
|
},
|
|
inp.v);
|
|
|
|
return Destroy{/*DestroyVar=*/std::move(maybeObject)};
|
|
}
|
|
|
|
Detach make(const parser::OmpClause::Detach &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDetachClause
|
|
return Detach{makeObject(inp.v.v, semaCtx)};
|
|
}
|
|
|
|
Device make(const parser::OmpClause::Device &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpDeviceClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpDeviceModifier::Value, Device::DeviceModifier,
|
|
// clang-format off
|
|
MS(Ancestor, Ancestor)
|
|
MS(Device_Num, DeviceNum)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpDeviceModifier>(mods);
|
|
auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);
|
|
return Device{{/*DeviceModifier=*/maybeApplyToV(convert, m0),
|
|
/*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::DeviceTypeDescription,
|
|
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.v -> OmpDoacrossClause
|
|
return makeDoacross(inp.v.v, semaCtx);
|
|
}
|
|
|
|
// DynamicAllocators: empty
|
|
|
|
Enter make(const parser::OmpClause::Enter &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpEnterClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpAutomapModifier::Value, Enter::Modifier,
|
|
// clang-format off
|
|
MS(Automap, Automap)
|
|
// clang-format on
|
|
);
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *mod = semantics::OmpGetUniqueModifier<parser::OmpAutomapModifier>(mods);
|
|
auto &objList = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
return Enter{{/*Modifier=*/maybeApplyToV(convert, mod),
|
|
/*List=*/makeObjects(objList, semaCtx)}};
|
|
}
|
|
|
|
Exclusive make(const parser::OmpClause::Exclusive &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Exclusive{makeObjects(/*List=*/inp.v, semaCtx)};
|
|
}
|
|
|
|
Fail make(const parser::OmpClause::Fail &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpFalClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, common::OmpMemoryOrderType, Fail::MemoryOrder,
|
|
// clang-format off
|
|
MS(Acq_Rel, AcqRel)
|
|
MS(Acquire, Acquire)
|
|
MS(Relaxed, Relaxed)
|
|
MS(Release, Release)
|
|
MS(Seq_Cst, SeqCst)
|
|
// clang-format on
|
|
);
|
|
|
|
return Fail{/*MemoryOrder=*/convert(inp.v.v)};
|
|
}
|
|
|
|
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::OmpFromClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpExpectation::Value, From::Expectation,
|
|
// clang-format off
|
|
MS(Present, Present)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
|
|
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
|
|
auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
|
|
auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto mappers = [&]() -> std::optional<List<Mapper>> {
|
|
if (t1)
|
|
return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
|
|
return std::nullopt;
|
|
}();
|
|
|
|
auto iterator = [&]() -> std::optional<Iterator> {
|
|
if (t2)
|
|
return makeIterator(*t2, semaCtx);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
return From{{/*Expectation=*/maybeApplyToV(convert, t0),
|
|
/*Mappers=*/std::move(mappers),
|
|
/*Iterator=*/std::move(iterator),
|
|
/*LocatorList=*/makeObjects(t3, semaCtx)}};
|
|
}
|
|
|
|
// Full: empty
|
|
|
|
Grainsize make(const parser::OmpClause::Grainsize &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpGrainsizeClause
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods);
|
|
auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);
|
|
return Grainsize{
|
|
{/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0),
|
|
/*Grainsize=*/makeExpr(t1, 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::OmpHintClause
|
|
return Hint{/*HintExpr=*/makeExpr(inp.v.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
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpDirectiveNameModifier>(mods);
|
|
auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t);
|
|
return If{
|
|
{/*DirectiveNameModifier=*/maybeApplyToV([](auto &&s) { return s; }, m0),
|
|
/*IfExpression=*/makeExpr(t1, semaCtx)}};
|
|
}
|
|
|
|
// Inbranch: empty
|
|
|
|
Inclusive make(const parser::OmpClause::Inclusive &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpObjectList
|
|
return Inclusive{makeObjects(/*List=*/inp.v, semaCtx)};
|
|
}
|
|
|
|
Indirect make(const parser::OmpClause::Indirect &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v.v -> std::optional<parser::ScalarLogicalExpr>
|
|
return Indirect{maybeApply(makeExprFn(semaCtx), inp.v.v)};
|
|
}
|
|
|
|
Init make(const parser::OmpClause::Init &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: init");
|
|
}
|
|
|
|
Initializer make(const parser::OmpClause::Initializer &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
llvm_unreachable("Empty: initializer");
|
|
}
|
|
|
|
InReduction make(const parser::OmpClause::InReduction &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpInReductionClause
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
assert(m0 && "OmpReductionIdentifier is required");
|
|
|
|
return InReduction{
|
|
{/*ReductionIdentifiers=*/{makeReductionOperator(*m0, 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
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpLastprivateModifier::Value,
|
|
Lastprivate::LastprivateModifier,
|
|
// clang-format off
|
|
MS(Conditional, Conditional)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpLastprivateModifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
return Lastprivate{{/*LastprivateModifier=*/maybeApplyToV(convert, m0),
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
Linear make(const parser::OmpClause::Linear &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp.v -> parser::OmpLinearClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpLinearModifier::Value, Linear::LinearModifier,
|
|
// clang-format off
|
|
MS(Ref, Ref)
|
|
MS(Val, Val)
|
|
MS(Uval, Uval)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpStepComplexModifier>(mods);
|
|
auto *m1 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpStepSimpleModifier>(mods);
|
|
assert((!m0 || !m1) && "Simple and complex modifiers both present");
|
|
|
|
auto *m2 = semantics::OmpGetUniqueModifier<parser::OmpLinearModifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto &&maybeStep = m0 ? maybeApplyToV(makeExprFn(semaCtx), m0)
|
|
: m1 ? maybeApplyToV(makeExprFn(semaCtx), m1)
|
|
: std::optional<Linear::StepComplexModifier>{};
|
|
|
|
return Linear{{/*StepComplexModifier=*/std::move(maybeStep),
|
|
/*LinearModifier=*/maybeApplyToV(convert, m2),
|
|
/*List=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
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
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convertMapType, parser::OmpMapType::Value, Map::MapType,
|
|
// clang-format off
|
|
MS(Alloc, Storage)
|
|
MS(Delete, Storage)
|
|
MS(Release, Storage)
|
|
MS(Storage, Storage)
|
|
MS(From, From)
|
|
MS(To, To)
|
|
MS(Tofrom, Tofrom)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convertMapTypeMod, parser::OmpMapTypeModifier::Value,
|
|
Map::MapTypeModifier,
|
|
// clang-format off
|
|
MS(Always, Always)
|
|
MS(Close, Close)
|
|
MS(Ompx_Hold, OmpxHold)
|
|
MS(Present, Present)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convertRefMod, parser::OmpRefModifier::Value, Map::RefModifier,
|
|
// clang-format off
|
|
MS(Ref_Ptee, RefPtee)
|
|
MS(Ref_Ptr, RefPtr)
|
|
MS(Ref_Ptr_Ptee, RefPtrPtee)
|
|
// clang-format on
|
|
);
|
|
|
|
// Treat always, close, present, self, delete modifiers as map-type-
|
|
// modifiers.
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
|
|
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapType>(mods);
|
|
auto &t2 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto type = [&]() -> std::optional<Map::MapType> {
|
|
if (t1)
|
|
return convertMapType(t1->v);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
llvm::DenseSet<Map::MapTypeModifier> modSet;
|
|
if (t1 && t1->v == parser::OmpMapType::Value::Delete)
|
|
modSet.insert(Map::MapTypeModifier::Delete);
|
|
|
|
for (auto *typeMod :
|
|
semantics::OmpGetRepeatableModifier<parser::OmpMapTypeModifier>(mods)) {
|
|
modSet.insert(convertMapTypeMod(typeMod->v));
|
|
}
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpAlwaysModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::Always);
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpCloseModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::Close);
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpDeleteModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::Delete);
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpPresentModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::Present);
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpSelfModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::Self);
|
|
if (semantics::OmpGetUniqueModifier<parser::OmpxHoldModifier>(mods))
|
|
modSet.insert(Map::MapTypeModifier::OmpxHold);
|
|
|
|
std::optional<Map::MapTypeModifiers> maybeTypeMods{};
|
|
if (!modSet.empty())
|
|
maybeTypeMods = Map::MapTypeModifiers(modSet.begin(), modSet.end());
|
|
|
|
auto refMod = [&]() -> std::optional<Map::RefModifier> {
|
|
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpRefModifier>(mods))
|
|
return convertRefMod(t->v);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
auto mappers = [&]() -> std::optional<List<Mapper>> {
|
|
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods))
|
|
return List<Mapper>{Mapper{makeObject(t->v, semaCtx)}};
|
|
return std::nullopt;
|
|
}();
|
|
|
|
auto iterator = [&]() -> std::optional<Iterator> {
|
|
if (auto *t = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods))
|
|
return makeIterator(*t, semaCtx);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
return Map{{/*MapType=*/std::move(type),
|
|
/*MapTypeModifiers=*/std::move(maybeTypeMods),
|
|
/*RefModifier=*/std::move(refMod), /*Mapper=*/std::move(mappers),
|
|
/*Iterator=*/std::move(iterator),
|
|
/*LocatorList=*/makeObjects(t2, semaCtx)}};
|
|
}
|
|
|
|
Match make(const parser::OmpClause::Match &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Match{};
|
|
}
|
|
|
|
// 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
|
|
// NoOpenmpConstructs: 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::OmpNumTasksClause
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 = semantics::OmpGetUniqueModifier<parser::OmpPrescriptiveness>(mods);
|
|
auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);
|
|
return NumTasks{{/*Prescriptiveness=*/maybeApplyToV(makePrescriptiveness, m0),
|
|
/*NumTasks=*/makeExpr(t1, 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::Value, Order::OrderModifier,
|
|
// clang-format off
|
|
MS(Reproducible, Reproducible)
|
|
MS(Unconstrained, Unconstrained)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert2, wrapped::Ordering, Order::Ordering,
|
|
// clang-format off
|
|
MS(Concurrent, Concurrent)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderModifier>(mods);
|
|
auto &t1 = std::get<wrapped::Ordering>(inp.v.t);
|
|
|
|
return Order{{/*OrderModifier=*/maybeApplyToV(convert1, 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)};
|
|
}
|
|
|
|
// See also Default.
|
|
Otherwise make(const parser::OmpClause::Otherwise &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Otherwise{};
|
|
}
|
|
|
|
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::AffinityPolicy, 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
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpReductionModifier::Value,
|
|
Reduction::ReductionModifier,
|
|
// clang-format off
|
|
MS(Inscan, Inscan)
|
|
MS(Task, Task)
|
|
MS(Default, Default)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpReductionModifier>(mods);
|
|
auto *m1 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
assert(m1 && "OmpReductionIdentifier is required");
|
|
|
|
return Reduction{
|
|
{/*ReductionModifier=*/maybeApplyToV(convert, m0),
|
|
/*ReductionIdentifiers=*/{makeReductionOperator(*m1, semaCtx)},
|
|
/*List=*/makeObjects(t1, 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::Kind, 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::OmpOrderingModifier::Value, Schedule::OrderingModifier,
|
|
// clang-format off
|
|
MS(Monotonic, Monotonic)
|
|
MS(Nonmonotonic, Nonmonotonic)
|
|
// clang-format on
|
|
);
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert3, parser::OmpChunkModifier::Value, Schedule::ChunkModifier,
|
|
// clang-format off
|
|
MS(Simd, Simd)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpOrderingModifier>(mods);
|
|
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpChunkModifier>(mods);
|
|
auto &t2 = std::get<wrapped::Kind>(inp.v.t);
|
|
auto &t3 = std::get<std::optional<parser::ScalarIntExpr>>(inp.v.t);
|
|
|
|
return Schedule{{/*Kind=*/convert1(t2),
|
|
/*OrderingModifier=*/maybeApplyToV(convert2, t0),
|
|
/*ChunkModifier=*/maybeApplyToV(convert3, t1),
|
|
/*ChunkSize=*/maybeApply(makeExprFn(semaCtx), t3)}};
|
|
}
|
|
|
|
// 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 &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *m0 =
|
|
semantics::OmpGetUniqueModifier<parser::OmpReductionIdentifier>(mods);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
assert(m0 && "OmpReductionIdentifier is required");
|
|
|
|
return TaskReduction{
|
|
{/*ReductionIdentifiers=*/{makeReductionOperator(*m0, 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::OmpToClause
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert, parser::OmpExpectation::Value, To::Expectation,
|
|
// clang-format off
|
|
MS(Present, Present)
|
|
// clang-format on
|
|
);
|
|
|
|
auto &mods = semantics::OmpGetModifiers(inp.v);
|
|
auto *t0 = semantics::OmpGetUniqueModifier<parser::OmpExpectation>(mods);
|
|
auto *t1 = semantics::OmpGetUniqueModifier<parser::OmpMapper>(mods);
|
|
auto *t2 = semantics::OmpGetUniqueModifier<parser::OmpIterator>(mods);
|
|
auto &t3 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
auto mappers = [&]() -> std::optional<List<Mapper>> {
|
|
if (t1)
|
|
return List<Mapper>{Mapper{makeObject(t1->v, semaCtx)}};
|
|
return std::nullopt;
|
|
}();
|
|
|
|
auto iterator = [&]() -> std::optional<Iterator> {
|
|
if (t2)
|
|
return makeIterator(*t2, semaCtx);
|
|
return std::nullopt;
|
|
}();
|
|
|
|
return To{{/*Expectation=*/maybeApplyToV(convert, t0),
|
|
/*Mappers=*/{std::move(mappers)},
|
|
/*Iterator=*/std::move(iterator),
|
|
/*LocatorList=*/makeObjects(t3, 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.v -> parser::OmpUpdateClause
|
|
if (inp.v) {
|
|
return common::visit(
|
|
[](auto &&s) { return Update{/*DependenceType=*/makeDepType(s)}; },
|
|
inp.v->u);
|
|
} else {
|
|
return Update{/*DependenceType=*/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 make(const parser::OmpClause::When &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return When{};
|
|
}
|
|
|
|
// Write: empty
|
|
} // namespace clause
|
|
|
|
Clause makeClause(const parser::OmpClause &cls,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return Fortran::common::visit( //
|
|
common::visitors{
|
|
[&](const parser::OmpClause::Default &s) {
|
|
using DSA = parser::OmpDefaultClause::DataSharingAttribute;
|
|
if (std::holds_alternative<DSA>(s.v.u)) {
|
|
return makeClause(llvm::omp::Clause::OMPC_default,
|
|
clause::makeDefault(s, semaCtx), cls.source);
|
|
} else {
|
|
return makeClause(llvm::omp::Clause::OMPC_otherwise,
|
|
clause::makeOtherwise(s, semaCtx), cls.source);
|
|
}
|
|
},
|
|
[&](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
|