#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>;
#define GEN_FLANG_CLAUSE_PARSER_KIND_MAP
#include "llvm/Frontend/OpenMP/OMP.inc"
}
}
static llvm::omp::Clause getClauseId(const Fortran::parser::OmpClause &clause) {
return Fortran::common::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) {
return const_cast<semantics::Symbol *>(&ref.get());
}
template <typename T>
static SymbolWithDesignator visit(T &&) {
return SymbolWithDesignator{};
}
template <typename T>
static SymbolWithDesignator visit(const evaluate::Designator<T> &e) {
return std::make_tuple(symbol_addr(*e.GetLastSymbol()),
evaluate::AsGenericExpr(AsRvalueRef(e)));
}
static SymbolWithDesignator visit(const evaluate::ProcedureDesignator &e) {
return std::make_tuple(symbol_addr(*e.GetSymbol()), std::nullopt);
}
template <typename T>
static SymbolWithDesignator visit(const evaluate::Expr<T> &e) {
return Fortran::common::visit([](auto &&s) { return visit(s); }, e.u);
}
static void verify(const SymbolWithDesignator &sd) {
const semantics::Symbol *symbol = std::get<0>(sd);
assert(symbol && "Expecting symbol");
auto &maybeDsg = std::get<1>(sd);
if (!maybeDsg)
return;
std::optional<evaluate::DataRef> maybeRef =
evaluate::ExtractDataRef(*maybeDsg);
if (maybeRef) {
if (&maybeRef->GetLastSymbol() == symbol)
return;
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 (const auto *name = std::get_if<parser::Name>(&object.u)) {
assert(name->symbol && "Expecting Symbol");
return Object{name->symbol, std::nullopt};
}
return makeObject(std::get<parser::Designator>(object.u), semaCtx);
}
std::optional<Object> getBaseObject(const Object &object,
semantics::SemanticsContext &semaCtx) {
if (!object.ref())
return std::nullopt;
auto maybeRef = evaluate::ExtractDataRef(*object.ref());
if (!maybeRef)
return std::nullopt;
evaluate::DataRef ref = *maybeRef;
if (std::get_if<evaluate::SymbolRef>(&ref.u)) {
return std::nullopt;
} else if (auto *comp = std::get_if<evaluate::Component>(&ref.u)) {
const evaluate::DataRef &base = comp->base();
return Object{
SymbolAndDesignatorExtractor::symbol_addr(base.GetLastSymbol()),
evaluate::AsGenericExpr(
SymbolAndDesignatorExtractor::AsRvalueRef(base))};
} else if (auto *arr = std::get_if<evaluate::ArrayRef>(&ref.u)) {
const evaluate::NamedEntity &base = arr->base();
evaluate::ExpressionAnalyzer ea{semaCtx};
if (auto *comp = base.UnwrapComponent()) {
return Object{SymbolAndDesignatorExtractor::symbol_addr(comp->symbol()),
ea.Designate(evaluate::DataRef{
SymbolAndDesignatorExtractor::AsRvalueRef(*comp)})};
} else if (base.UnwrapSymbolRef()) {
return std::nullopt;
}
} else {
assert(std::holds_alternative<evaluate::CoarrayRef>(ref.u) &&
"Unexpected variant alternative");
llvm_unreachable("Coarray reference not supported at the moment");
}
return std::nullopt;
}
#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(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);
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(When, When);
DefinedOperator makeDefinedOperator(const parser::DefinedOperator &inp,
semantics::SemanticsContext &semaCtx) {
CLAUSET_ENUM_CONVERT(
convert, parser::DefinedOperator::IntrinsicOperator,
DefinedOperator::IntrinsicOperator,
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)
);
return Fortran::common::visit(
common::visitors{
[&](const parser::DefinedOpName &s) {
return DefinedOperator{
DefinedOperator::DefinedOpName{makeObject(s.v, semaCtx)}};
},
[&](const parser::DefinedOperator::IntrinsicOperator &s) {
return DefinedOperator{convert(s)};
},
},
inp.u);
}
ProcedureDesignator
makeProcedureDesignator(const parser::ProcedureDesignator &inp,
semantics::SemanticsContext &semaCtx) {
return ProcedureDesignator{Fortran::common::visit(
common::visitors{
[&](const parser::Name &t) { return makeObject(t, semaCtx); },
[&](const parser::ProcComponentRef &t) {
return makeObject(t.v.thing, semaCtx);
},
},
inp.u)};
}
ReductionOperator makeReductionOperator(const parser::OmpReductionOperator &inp,
semantics::SemanticsContext &semaCtx) {
return Fortran::common::visit(
common::visitors{
[&](const parser::DefinedOperator &s) {
return ReductionOperator{makeDefinedOperator(s, semaCtx)};
},
[&](const parser::ProcedureDesignator &s) {
return ReductionOperator{makeProcedureDesignator(s, semaCtx)};
},
},
inp.u);
}
Affinity make(const parser::OmpClause::Affinity &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: affinity");
}
Align make(const parser::OmpClause::Align &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: align");
}
Aligned make(const parser::OmpClause::Aligned &inp,
semantics::SemanticsContext &semaCtx) {
auto &t0 = std::get<parser::OmpObjectList>(inp.v.t);
auto &t1 = std::get<std::optional<parser::ScalarIntConstantExpr>>(inp.v.t);
return Aligned{{
maybeApply(makeExprFn(semaCtx), t1),
makeObjects(t0, semaCtx),
}};
}
Allocate make(const parser::OmpClause::Allocate &inp,
semantics::SemanticsContext &semaCtx) {
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{{std::nullopt,
std::nullopt,
std::nullopt,
makeObjects(t1, semaCtx)}};
}
using Tuple = decltype(Allocate::t);
return Allocate{Fortran::common::visit(
common::visitors{
[&](const wrapped::AllocateModifier::Allocator &v) -> Tuple {
return {makeExpr(v.v, semaCtx),
std::nullopt,
std::nullopt,
makeObjects(t1, semaCtx)};
},
[&](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 {
std::nullopt,
Allocator{makeExpr(s0.v, semaCtx)},
Align{makeExpr(s1.v, semaCtx)},
makeObjects(t1, semaCtx)};
},
[&](const wrapped::AllocateModifier::Align &v) -> Tuple {
return {std::nullopt,
std::nullopt,
Align{makeExpr(v.v, semaCtx)},
makeObjects(t1, semaCtx)};
},
},
t0->u)};
}
Allocator make(const parser::OmpClause::Allocator &inp,
semantics::SemanticsContext &semaCtx) {
return Allocator{makeExpr(inp.v, semaCtx)};
}
At make(const parser::OmpClause::At &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: at");
}
AtomicDefaultMemOrder make(const parser::OmpClause::AtomicDefaultMemOrder &inp,
semantics::SemanticsContext &semaCtx) {
CLAUSET_ENUM_CONVERT(
convert, common::OmpAtomicDefaultMemOrderType,
AtomicDefaultMemOrder::MemoryOrder,
MS(AcqRel, AcqRel)
MS(Relaxed, Relaxed)
MS(SeqCst, SeqCst)
);
return AtomicDefaultMemOrder{convert(inp.v.v)};
}
Bind make(const parser::OmpClause::Bind &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: bind");
}
Collapse make(const parser::OmpClause::Collapse &inp,
semantics::SemanticsContext &semaCtx) {
return Collapse{makeExpr(inp.v, semaCtx)};
}
Copyin make(const parser::OmpClause::Copyin &inp,
semantics::SemanticsContext &semaCtx) {
return Copyin{makeObjects(inp.v, semaCtx)};
}
Copyprivate make(const parser::OmpClause::Copyprivate &inp,
semantics::SemanticsContext &semaCtx) {
return Copyprivate{makeObjects(inp.v, semaCtx)};
}
Default make(const parser::OmpClause::Default &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpDefaultClause;
CLAUSET_ENUM_CONVERT(
convert, wrapped::Type, Default::DataSharingAttribute,
MS(Firstprivate, Firstprivate)
MS(None, None)
MS(Private, Private)
MS(Shared, Shared)
);
return Default{convert(inp.v.v)};
}
Defaultmap make(const parser::OmpClause::Defaultmap &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpDefaultmapClause;
CLAUSET_ENUM_CONVERT(
convert1, wrapped::ImplicitBehavior, Defaultmap::ImplicitBehavior,
MS(Alloc, Alloc)
MS(To, To)
MS(From, From)
MS(Tofrom, Tofrom)
MS(Firstprivate, Firstprivate)
MS(None, None)
MS(Default, Default)
);
CLAUSET_ENUM_CONVERT(
convert2, wrapped::VariableCategory, Defaultmap::VariableCategory,
MS(Scalar, Scalar)
MS(Aggregate, Aggregate)
MS(Pointer, Pointer)
MS(Allocatable, Allocatable)
);
auto &t0 = std::get<wrapped::ImplicitBehavior>(inp.v.t);
auto &t1 = std::get<std::optional<wrapped::VariableCategory>>(inp.v.t);
return Defaultmap{{convert1(t0),
maybeApply(convert2, t1)}};
}
Depend make(const parser::OmpClause::Depend &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpDependClause;
using Variant = decltype(Depend::u);
using Iteration = Doacross::Vector::value_type;
CLAUSET_ENUM_CONVERT(
convert1, parser::OmpDependenceType::Type, Depend::TaskDependenceType,
MS(In, In)
MS(Out, Out)
MS(Inout, Inout)
);
return Depend{Fortran::common::visit(
common::visitors{
[&](const wrapped::Source &s) -> Variant {
return Doacross{
{Doacross::DependenceType::Source,
{}}};
},
[&](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{{Doacross::DependenceType::Sink,
makeList(s.v, convert2)}};
},
[&](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{
{convert1(t0.v),
std::nullopt,
makeList(t1, convert4)}};
},
},
inp.v.u)};
}
Destroy make(const parser::OmpClause::Destroy &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: destroy");
}
Detach make(const parser::OmpClause::Detach &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: detach");
}
Device make(const parser::OmpClause::Device &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpDeviceClause;
CLAUSET_ENUM_CONVERT(
convert, parser::OmpDeviceClause::DeviceModifier, Device::DeviceModifier,
MS(Ancestor, Ancestor)
MS(Device_Num, DeviceNum)
);
auto &t0 = std::get<std::optional<wrapped::DeviceModifier>>(inp.v.t);
auto &t1 = std::get<parser::ScalarIntExpr>(inp.v.t);
return Device{{maybeApply(convert, t0),
makeExpr(t1, semaCtx)}};
}
DeviceType make(const parser::OmpClause::DeviceType &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpDeviceTypeClause;
CLAUSET_ENUM_CONVERT(
convert, wrapped::Type, DeviceType::DeviceTypeDescription,
MS(Any, Any)
MS(Host, Host)
MS(Nohost, Nohost)
);
return DeviceType{convert(inp.v.v)};
}
DistSchedule make(const parser::OmpClause::DistSchedule &inp,
semantics::SemanticsContext &semaCtx) {
return DistSchedule{{DistSchedule::Kind::Static,
maybeApply(makeExprFn(semaCtx), inp.v)}};
}
Doacross make(const parser::OmpClause::Doacross &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: doacross");
}
Enter make(const parser::OmpClause::Enter &inp,
semantics::SemanticsContext &semaCtx) {
return Enter{makeObjects(inp.v, semaCtx)};
}
Exclusive make(const parser::OmpClause::Exclusive &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: exclusive");
}
Fail make(const parser::OmpClause::Fail &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: fail");
}
Filter make(const parser::OmpClause::Filter &inp,
semantics::SemanticsContext &semaCtx) {
return Filter{makeExpr(inp.v, semaCtx)};
}
Final make(const parser::OmpClause::Final &inp,
semantics::SemanticsContext &semaCtx) {
return Final{makeExpr(inp.v, semaCtx)};
}
Firstprivate make(const parser::OmpClause::Firstprivate &inp,
semantics::SemanticsContext &semaCtx) {
return Firstprivate{makeObjects(inp.v, semaCtx)};
}
From make(const parser::OmpClause::From &inp,
semantics::SemanticsContext &semaCtx) {
return From{{std::nullopt, std::nullopt,
std::nullopt,
makeObjects(inp.v, semaCtx)}};
}
Grainsize make(const parser::OmpClause::Grainsize &inp,
semantics::SemanticsContext &semaCtx) {
return Grainsize{{std::nullopt,
makeExpr(inp.v, semaCtx)}};
}
HasDeviceAddr make(const parser::OmpClause::HasDeviceAddr &inp,
semantics::SemanticsContext &semaCtx) {
return HasDeviceAddr{makeObjects(inp.v, semaCtx)};
}
Hint make(const parser::OmpClause::Hint &inp,
semantics::SemanticsContext &semaCtx) {
return Hint{makeExpr(inp.v, semaCtx)};
}
If make(const parser::OmpClause::If &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpIfClause;
CLAUSET_ENUM_CONVERT(
convert, wrapped::DirectiveNameModifier, llvm::omp::Directive,
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)
);
auto &t0 = std::get<std::optional<wrapped::DirectiveNameModifier>>(inp.v.t);
auto &t1 = std::get<parser::ScalarLogicalExpr>(inp.v.t);
return If{{maybeApply(convert, t0),
makeExpr(t1, semaCtx)}};
}
Inclusive make(const parser::OmpClause::Inclusive &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: inclusive");
}
Indirect make(const parser::OmpClause::Indirect &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: indirect");
}
Init make(const parser::OmpClause::Init &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: init");
}
InReduction make(const parser::OmpClause::InReduction &inp,
semantics::SemanticsContext &semaCtx) {
auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t);
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
return InReduction{
{{makeReductionOperator(t0, semaCtx)},
makeObjects(t1, semaCtx)}};
}
IsDevicePtr make(const parser::OmpClause::IsDevicePtr &inp,
semantics::SemanticsContext &semaCtx) {
return IsDevicePtr{makeObjects(inp.v, semaCtx)};
}
Lastprivate make(const parser::OmpClause::Lastprivate &inp,
semantics::SemanticsContext &semaCtx) {
return Lastprivate{{std::nullopt,
makeObjects(inp.v, semaCtx)}};
}
Linear make(const parser::OmpClause::Linear &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpLinearClause;
CLAUSET_ENUM_CONVERT(
convert, parser::OmpLinearModifier::Type, Linear::LinearModifier,
MS(Ref, Ref)
MS(Val, Val)
MS(Uval, Uval)
);
using Tuple = decltype(Linear::t);
return Linear{Fortran::common::visit(
common::visitors{
[&](const wrapped::WithModifier &s) -> Tuple {
return {
std::nullopt,
maybeApply(makeExprFn(semaCtx), s.step),
convert(s.modifier.v),
makeList(s.names, makeObjectFn(semaCtx))};
},
[&](const wrapped::WithoutModifier &s) -> Tuple {
return {
maybeApply(makeExprFn(semaCtx), s.step),
std::nullopt,
std::nullopt,
makeList(s.names, makeObjectFn(semaCtx))};
},
},
inp.v.u)};
}
Link make(const parser::OmpClause::Link &inp,
semantics::SemanticsContext &semaCtx) {
return Link{makeObjects(inp.v, semaCtx)};
}
Map make(const parser::OmpClause::Map &inp,
semantics::SemanticsContext &semaCtx) {
CLAUSET_ENUM_CONVERT(
convert1, parser::OmpMapType::Type, Map::MapType,
MS(To, To)
MS(From, From)
MS(Tofrom, Tofrom)
MS(Alloc, Alloc)
MS(Release, Release)
MS(Delete, Delete)
);
auto &t0 = std::get<std::optional<parser::OmpMapType>>(inp.v.t);
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
if (!t0) {
return Map{{std::nullopt, std::nullopt,
std::nullopt, std::nullopt,
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{{convert1(s1),
maybeList,
std::nullopt, std::nullopt,
makeObjects(t1, semaCtx)}};
}
Message make(const parser::OmpClause::Message &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: message");
}
Nocontext make(const parser::OmpClause::Nocontext &inp,
semantics::SemanticsContext &semaCtx) {
return Nocontext{makeExpr(inp.v, semaCtx)};
}
Nontemporal make(const parser::OmpClause::Nontemporal &inp,
semantics::SemanticsContext &semaCtx) {
return Nontemporal{makeList(inp.v, makeObjectFn(semaCtx))};
}
Novariants make(const parser::OmpClause::Novariants &inp,
semantics::SemanticsContext &semaCtx) {
return Novariants{makeExpr(inp.v, semaCtx)};
}
NumTasks make(const parser::OmpClause::NumTasks &inp,
semantics::SemanticsContext &semaCtx) {
return NumTasks{{std::nullopt,
makeExpr(inp.v, semaCtx)}};
}
NumTeams make(const parser::OmpClause::NumTeams &inp,
semantics::SemanticsContext &semaCtx) {
return NumTeams{{std::nullopt,
makeExpr(inp.v, semaCtx)}};
}
NumThreads make(const parser::OmpClause::NumThreads &inp,
semantics::SemanticsContext &semaCtx) {
return NumThreads{makeExpr(inp.v, semaCtx)};
}
OmpxDynCgroupMem make(const parser::OmpClause::OmpxDynCgroupMem &inp,
semantics::SemanticsContext &semaCtx) {
return OmpxDynCgroupMem{makeExpr(inp.v, semaCtx)};
}
Order make(const parser::OmpClause::Order &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpOrderClause;
CLAUSET_ENUM_CONVERT(
convert1, parser::OmpOrderModifier::Kind, Order::OrderModifier,
MS(Reproducible, Reproducible)
MS(Unconstrained, Unconstrained)
);
CLAUSET_ENUM_CONVERT(
convert2, wrapped::Type, Order::Ordering,
MS(Concurrent, Concurrent)
);
auto &t0 = std::get<std::optional<parser::OmpOrderModifier>>(inp.v.t);
auto &t1 = std::get<wrapped::Type>(inp.v.t);
auto convert3 = [&](const parser::OmpOrderModifier &s) {
return Fortran::common::visit(
[&](parser::OmpOrderModifier::Kind k) { return convert1(k); }, s.u);
};
return Order{
{maybeApply(convert3, t0), convert2(t1)}};
}
Ordered make(const parser::OmpClause::Ordered &inp,
semantics::SemanticsContext &semaCtx) {
return Ordered{maybeApply(makeExprFn(semaCtx), inp.v)};
}
Partial make(const parser::OmpClause::Partial &inp,
semantics::SemanticsContext &semaCtx) {
return Partial{maybeApply(makeExprFn(semaCtx), inp.v)};
}
Priority make(const parser::OmpClause::Priority &inp,
semantics::SemanticsContext &semaCtx) {
return Priority{makeExpr(inp.v, semaCtx)};
}
Private make(const parser::OmpClause::Private &inp,
semantics::SemanticsContext &semaCtx) {
return Private{makeObjects(inp.v, semaCtx)};
}
ProcBind make(const parser::OmpClause::ProcBind &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpProcBindClause;
CLAUSET_ENUM_CONVERT(
convert, wrapped::Type, ProcBind::AffinityPolicy,
MS(Close, Close)
MS(Master, Master)
MS(Spread, Spread)
MS(Primary, Primary)
);
return ProcBind{convert(inp.v.v)};
}
Reduction make(const parser::OmpClause::Reduction &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpReductionClause;
CLAUSET_ENUM_CONVERT(
convert, wrapped::ReductionModifier, Reduction::ReductionModifier,
MS(Inscan, Inscan)
MS(Task, Task)
MS(Default, Default)
);
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{
{t0
? std::make_optional<Reduction::ReductionModifier>(convert(*t0))
: std::nullopt,
{makeReductionOperator(t1, semaCtx)},
makeObjects(t2, semaCtx)}};
}
Safelen make(const parser::OmpClause::Safelen &inp,
semantics::SemanticsContext &semaCtx) {
return Safelen{makeExpr(inp.v, semaCtx)};
}
Schedule make(const parser::OmpClause::Schedule &inp,
semantics::SemanticsContext &semaCtx) {
using wrapped = parser::OmpScheduleClause;
CLAUSET_ENUM_CONVERT(
convert1, wrapped::ScheduleType, Schedule::Kind,
MS(Static, Static)
MS(Dynamic, Dynamic)
MS(Guided, Guided)
MS(Auto, Auto)
MS(Runtime, Runtime)
);
CLAUSET_ENUM_CONVERT(
convert2, parser::OmpScheduleModifierType::ModType,
Schedule::OrderingModifier,
MS(Monotonic, Monotonic)
MS(Nonmonotonic, Nonmonotonic)
);
CLAUSET_ENUM_CONVERT(
convert3, parser::OmpScheduleModifierType::ModType,
Schedule::ChunkModifier,
MS(Simd, Simd)
);
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{{convert1(t1), std::nullopt,
std::nullopt,
maybeApply(makeExprFn(semaCtx), t2)}};
}
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) {
cmod = convert3(m1.v.v);
if (m2)
omod = convert2(m2->v.v);
} else {
omod = convert2(m1.v.v);
if (m2)
cmod = convert3(m2->v.v);
}
return Schedule{{convert1(t1),
omod,
cmod,
maybeApply(makeExprFn(semaCtx), t2)}};
}
Severity make(const parser::OmpClause::Severity &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: severity");
}
Shared make(const parser::OmpClause::Shared &inp,
semantics::SemanticsContext &semaCtx) {
return Shared{makeObjects(inp.v, semaCtx)};
}
Simdlen make(const parser::OmpClause::Simdlen &inp,
semantics::SemanticsContext &semaCtx) {
return Simdlen{makeExpr(inp.v, semaCtx)};
}
Sizes make(const parser::OmpClause::Sizes &inp,
semantics::SemanticsContext &semaCtx) {
return Sizes{makeList(inp.v, makeExprFn(semaCtx))};
}
TaskReduction make(const parser::OmpClause::TaskReduction &inp,
semantics::SemanticsContext &semaCtx) {
auto &t0 = std::get<parser::OmpReductionOperator>(inp.v.t);
auto &t1 = std::get<parser::OmpObjectList>(inp.v.t);
return TaskReduction{
{{makeReductionOperator(t0, semaCtx)},
makeObjects(t1, semaCtx)}};
}
ThreadLimit make(const parser::OmpClause::ThreadLimit &inp,
semantics::SemanticsContext &semaCtx) {
return ThreadLimit{makeExpr(inp.v, semaCtx)};
}
To make(const parser::OmpClause::To &inp,
semantics::SemanticsContext &semaCtx) {
return To{{std::nullopt, std::nullopt,
std::nullopt,
makeObjects(inp.v, semaCtx)}};
}
Uniform make(const parser::OmpClause::Uniform &inp,
semantics::SemanticsContext &semaCtx) {
return Uniform{makeList(inp.v, makeObjectFn(semaCtx))};
}
Update make(const parser::OmpClause::Update &inp,
semantics::SemanticsContext &semaCtx) {
return Update{std::nullopt};
}
Use make(const parser::OmpClause::Use &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: use");
}
UseDeviceAddr make(const parser::OmpClause::UseDeviceAddr &inp,
semantics::SemanticsContext &semaCtx) {
return UseDeviceAddr{makeObjects(inp.v, semaCtx)};
}
UseDevicePtr make(const parser::OmpClause::UseDevicePtr &inp,
semantics::SemanticsContext &semaCtx) {
return UseDevicePtr{makeObjects(inp.v, semaCtx)};
}
UsesAllocators make(const parser::OmpClause::UsesAllocators &inp,
semantics::SemanticsContext &semaCtx) {
llvm_unreachable("Empty: uses_allocators");
}
}
Clause makeClause(const parser::OmpClause &cls,
semantics::SemanticsContext &semaCtx) {
return Fortran::common::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; });
if (found != from.end()) {
clause.source = found->source;
} else {
allDone = false;
}
}
return allDone;
}
}