A compound construct with a list of clauses is broken up into individual
leaf/composite constructs. Each such construct has the list of clauses
that apply to it based on the OpenMP spec.
Each lowering function (i.e. a function that generates MLIR ops) is now
responsible for generating its body as described below.
Functions that receive AST nodes extract the construct, and the clauses
from the node. They then create a work queue consisting of individual
constructs, and invoke a common dispatch function to process (lower) the
queue.
The dispatch function examines the current position in the queue, and
invokes the appropriate lowering function. Each lowering function
receives the queue as well, and once it needs to generate its body, it
either invokes the dispatch function on the rest of the queue (if any),
or processes nested evaluations if the work queue is at the end.
Re-application of ca1bd5995f with fixes for
compilation errors.
1254 lines
42 KiB
C++
1254 lines
42 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 detail {
|
|
template <typename C>
|
|
llvm::omp::Clause getClauseIdForClass(C &&) {
|
|
using namespace Fortran;
|
|
using A = llvm::remove_cvref_t<C>; // A is referenced in OMP.inc
|
|
// The code included below contains a sequence of checks like the following
|
|
// for each OpenMP clause
|
|
// if constexpr (std::is_same_v<A, parser::OmpClause::AcqRel>)
|
|
// return llvm::omp::Clause::OMPC_acq_rel;
|
|
// [...]
|
|
#define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
|
|
#include "llvm/Frontend/OpenMP/OMP.inc"
|
|
}
|
|
} // namespace detail
|
|
|
|
static llvm::omp::Clause getClauseId(const Fortran::parser::OmpClause &clause) {
|
|
return std::visit([](auto &&s) { return detail::getClauseIdForClass(s); },
|
|
clause.u);
|
|
}
|
|
|
|
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 std::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 std::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,
|
|
Fortran::semantics::SemanticsContext &semaCtx) {
|
|
// If it's just the symbol, then there is no base.
|
|
if (!object.id())
|
|
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, ); // missing-in-parser
|
|
// MAKE_EMPTY_CLASS(NoOpenmpRoutines, ); // missing-in-parser
|
|
// MAKE_EMPTY_CLASS(NoParallelism, ); // missing-in-parser
|
|
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);
|
|
|
|
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 std::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{std::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 std::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: missing-in-parser
|
|
// AcqRel: empty
|
|
// Acquire: empty
|
|
// AdjustArgs: incomplete
|
|
|
|
Affinity make(const parser::OmpClause::Affinity &inp,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
// inp -> empty
|
|
llvm_unreachable("Empty: affinity");
|
|
}
|
|
|
|
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{std::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: missing-in-parser
|
|
|
|
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{std::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: missing-in-parser
|
|
|
|
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::OmpObjectList
|
|
return Lastprivate{{/*LastprivateModifier=*/std::nullopt,
|
|
/*List=*/makeObjects(inp.v, 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{std::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
|
|
|
|
CLAUSET_ENUM_CONVERT( //
|
|
convert1, parser::OmpMapType::Type, Map::MapType,
|
|
// clang-format off
|
|
MS(To, To)
|
|
MS(From, From)
|
|
MS(Tofrom, Tofrom)
|
|
MS(Alloc, Alloc)
|
|
MS(Release, Release)
|
|
MS(Delete, Delete)
|
|
// clang-format on
|
|
);
|
|
|
|
// No convert2: MapTypeModifier is not an enum in parser.
|
|
|
|
auto &t0 = std::get<std::optional<parser::OmpMapType>>(inp.v.t);
|
|
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
|
|
|
|
if (!t0) {
|
|
return Map{{/*MapType=*/std::nullopt, /*MapTypeModifiers=*/std::nullopt,
|
|
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
|
|
/*LocatorList=*/makeObjects(t1, semaCtx)}};
|
|
}
|
|
|
|
auto &s0 = std::get<std::optional<parser::OmpMapType::Always>>(t0->t);
|
|
auto &s1 = std::get<parser::OmpMapType::Type>(t0->t);
|
|
|
|
std::optional<Map::MapTypeModifiers> maybeList;
|
|
if (s0)
|
|
maybeList = Map::MapTypeModifiers{Map::MapTypeModifier::Always};
|
|
|
|
return Map{{/*MapType=*/convert1(s1),
|
|
/*MapTypeModifiers=*/maybeList,
|
|
/*Mapper=*/std::nullopt, /*Iterator=*/std::nullopt,
|
|
/*LocatorList=*/makeObjects(t1, 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: missing-in-parser
|
|
// NoOpenmpRoutines: missing-in-parser
|
|
// NoParallelism: missing-in-parser
|
|
// 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
|
|
return NumTeams{{/*LowerBound=*/std::nullopt,
|
|
/*UpperBound=*/makeExpr(inp.v, semaCtx)}};
|
|
}
|
|
|
|
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 std::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))};
|
|
}
|
|
|
|
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 Fortran::parser::OmpClause &cls,
|
|
semantics::SemanticsContext &semaCtx) {
|
|
return std::visit(
|
|
[&](auto &&s) {
|
|
return makeClause(getClauseId(cls), 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
|