
OpenMP 6.0 has changed the modifiers on the MAP clause: - map-type-modifier has been split into individual modifiers, - map-type "delete" has become a modifier, - new modifiers have been added. This patch adds parsing support for all of the OpenMP 6.0 modifiers. The old "map-type-modifier" is retained, but is no longer created in parsing. It will remain to take advantage of the preexisting modifier validation for older versions: when the OpenMP version is < 6.0, the modifiers will be rewritten back as map-type-modifiers (or map- type in case of "delete"). In this patch the modifiers will always be rewritten in the older format to isolate these changes to parsing as much as possible.
641 lines
14 KiB
C++
641 lines
14 KiB
C++
//===-- flang/lib/Semantics/openmp-modifiers.cpp --------------------------===//
|
|
//
|
|
// 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/Semantics/openmp-modifiers.h"
|
|
|
|
#include "flang/Parser/parse-tree.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/Frontend/OpenMP/OMP.h"
|
|
|
|
#include <algorithm>
|
|
#include <cassert>
|
|
#include <map>
|
|
|
|
namespace Fortran::semantics {
|
|
using namespace llvm::omp;
|
|
|
|
/// Find the highest version that exists as a key in the given map,
|
|
/// and is less than or equal to `version`.
|
|
/// Account for "version" not being a value from getOpenMPVersions().
|
|
template <typename ValueTy>
|
|
static unsigned findVersion(
|
|
unsigned version, const std::map<unsigned, ValueTy> &map) {
|
|
llvm::ArrayRef<unsigned> versions{llvm::omp::getOpenMPVersions()};
|
|
assert(!versions.empty() && "getOpenMPVersions returned empty list");
|
|
version = std::clamp(version, versions.front(), versions.back());
|
|
|
|
// std::map is sorted with respect to keys, by default in the ascending
|
|
// order.
|
|
unsigned found{0};
|
|
for (auto &[v, _] : map) {
|
|
if (v <= version) {
|
|
found = v;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// It can happen that the above search will not find any version, for
|
|
// example when the minimum version in the map is higher than the current
|
|
// version. This is really an error, but this situation should be handled
|
|
// gracefully, so make some sensible choice and return it.
|
|
if (found == 0) {
|
|
found = !map.empty() ? map.begin()->first : versions.front();
|
|
}
|
|
return found;
|
|
}
|
|
|
|
const OmpProperties &OmpModifierDescriptor::props(unsigned version) const {
|
|
return props_.at(findVersion(version, props_));
|
|
}
|
|
|
|
const OmpClauses &OmpModifierDescriptor::clauses(unsigned version) const {
|
|
return clauses_.at(findVersion(version, clauses_));
|
|
}
|
|
|
|
unsigned OmpModifierDescriptor::since(llvm::omp::Clause id) const {
|
|
unsigned found{[&]() {
|
|
for (auto &[v, cs] : clauses_) {
|
|
if (cs.test(id)) {
|
|
return v;
|
|
}
|
|
}
|
|
return ~0u;
|
|
}()};
|
|
|
|
return found <= 45 ? 0 : found;
|
|
}
|
|
|
|
// Note: The intent for these functions is to have them be automatically-
|
|
// generated in the future.
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignment>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"alignment",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique, OmpProperty::Ultimate, OmpProperty::Post}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_aligned}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlignModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"align-modifier",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_allocate}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpAllocatorComplexModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"allocator-complex-modifier",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_allocate}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpAllocatorSimpleModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"allocator-simple-modifier",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Exclusive, OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{50, {Clause::OMPC_allocate}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpAlwaysModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"always-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpChunkModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"chunk-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_schedule}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpCloseModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"close-modifier",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{50, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpContextSelector>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"context-selector",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Required, OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
// The MATCH clause takes a selector as an argument, not modifier.
|
|
{50, {Clause::OMPC_when}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeleteModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"delete-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique, OmpProperty::Ultimate}},
|
|
{60, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDependenceType>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"dependence-type",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Required, OmpProperty::Ultimate}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_depend}},
|
|
{51, {Clause::OMPC_depend, Clause::OMPC_update}},
|
|
{52, {Clause::OMPC_doacross}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpDeviceModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"device-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_device}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpDirectiveNameModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"directive-name-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_if}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpExpectation>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"expectation",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_from, Clause::OMPC_to}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropPreference>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"interop-preference",
|
|
/*props=*/
|
|
{
|
|
{52, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{52, {Clause::OMPC_init}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpInteropType>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"interop-type",
|
|
/*props=*/
|
|
{
|
|
{52, {OmpProperty::Required}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{52, {Clause::OMPC_init}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpIterator>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"iterator",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{50, {Clause::OMPC_affinity, Clause::OMPC_depend}},
|
|
{51,
|
|
{Clause::OMPC_affinity, Clause::OMPC_depend, Clause::OMPC_from,
|
|
Clause::OMPC_map, Clause::OMPC_to}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpLastprivateModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"lastprivate-modifier",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{50, {Clause::OMPC_lastprivate}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpLinearModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"linear-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_linear}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <> //
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapper>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"mapper",
|
|
/*props=*/
|
|
{
|
|
{50, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{50, {Clause::OMPC_from, Clause::OMPC_map, Clause::OMPC_to}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapType>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"map-type",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Ultimate}},
|
|
{60, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpMapTypeModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"map-type-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {}}, // Repeatable
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_map}},
|
|
{60, {}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"order-modifier",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_order}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpOrderingModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"ordering-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_schedule}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPrescriptiveness>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"prescriptiveness",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_grainsize, Clause::OMPC_num_tasks}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpPresentModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"present-modifier",
|
|
/*props=*/
|
|
{
|
|
{51, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{51, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpReductionIdentifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"reduction-identifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Required, OmpProperty::Ultimate}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_reduction}},
|
|
{50,
|
|
{Clause::OMPC_in_reduction, Clause::OMPC_reduction,
|
|
Clause::OMPC_task_reduction}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpReductionModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"reduction-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_reduction}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpRefModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"ref-modifier",
|
|
/*props=*/
|
|
{
|
|
{60, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{60, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpSelfModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"self-modifier",
|
|
/*props=*/
|
|
{
|
|
{60, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{60, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &
|
|
OmpGetDescriptor<parser::OmpStepComplexModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"step-complex-modifier",
|
|
/*props=*/
|
|
{
|
|
{52, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{52, {Clause::OMPC_linear}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpStepSimpleModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"step-simple-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique, OmpProperty::Exclusive}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_linear}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpTaskDependenceType>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"task-dependence-type",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Required, OmpProperty::Ultimate}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_depend}},
|
|
{51, {Clause::OMPC_depend, Clause::OMPC_update}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpVariableCategory>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"variable-category",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Required, OmpProperty::Unique}},
|
|
{50, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_defaultmap}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
|
|
template <>
|
|
const OmpModifierDescriptor &OmpGetDescriptor<parser::OmpxHoldModifier>() {
|
|
static const OmpModifierDescriptor desc{
|
|
/*name=*/"ompx-hold-modifier",
|
|
/*props=*/
|
|
{
|
|
{45, {OmpProperty::Unique}},
|
|
},
|
|
/*clauses=*/
|
|
{
|
|
{45, {Clause::OMPC_map}},
|
|
},
|
|
};
|
|
return desc;
|
|
}
|
|
} // namespace Fortran::semantics
|