summaryrefslogtreecommitdiff
path: root/flang/lib/Semantics/check-omp-structure.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Semantics/check-omp-structure.cpp')
-rw-r--r--flang/lib/Semantics/check-omp-structure.cpp95
1 files changed, 90 insertions, 5 deletions
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 54ce45157537..e5baddf59940 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2378,6 +2378,87 @@ bool OmpStructureChecker::CheckIntrinsicOperator(
return false;
}
+static bool IsReductionAllowedForType(
+ const parser::OmpClause::Reduction &x, const DeclTypeSpec &type) {
+ const auto &definedOp{std::get<parser::OmpReductionOperator>(x.v.t)};
+ // TODO: user defined reduction operators. Just allow everything for now.
+ bool ok{true};
+
+ auto IsLogical{[](const DeclTypeSpec &type) -> bool {
+ return type.category() == DeclTypeSpec::Logical;
+ }};
+ auto IsCharacter{[](const DeclTypeSpec &type) -> bool {
+ return type.category() == DeclTypeSpec::Character;
+ }};
+
+ common::visit(
+ common::visitors{
+ [&](const parser::DefinedOperator &dOpr) {
+ if (const auto *intrinsicOp{
+ std::get_if<parser::DefinedOperator::IntrinsicOperator>(
+ &dOpr.u)}) {
+ // OMP5.2: The type [...] of a list item that appears in a
+ // reduction clause must be valid for the combiner expression
+ // See F2023: Table 10.2
+ // .LT., .LE., .GT., .GE. are handled as procedure designators
+ // below.
+ switch (*intrinsicOp) {
+ case parser::DefinedOperator::IntrinsicOperator::Multiply:
+ [[fallthrough]];
+ case parser::DefinedOperator::IntrinsicOperator::Add:
+ [[fallthrough]];
+ case parser::DefinedOperator::IntrinsicOperator::Subtract:
+ ok = type.IsNumeric(TypeCategory::Integer) ||
+ type.IsNumeric(TypeCategory::Real) ||
+ type.IsNumeric(TypeCategory::Complex);
+ break;
+
+ case parser::DefinedOperator::IntrinsicOperator::AND:
+ [[fallthrough]];
+ case parser::DefinedOperator::IntrinsicOperator::OR:
+ [[fallthrough]];
+ case parser::DefinedOperator::IntrinsicOperator::EQV:
+ [[fallthrough]];
+ case parser::DefinedOperator::IntrinsicOperator::NEQV:
+ ok = IsLogical(type);
+ break;
+
+ // Reduction identifier is not in OMP5.2 Table 5.2
+ default:
+ DIE("This should have been caught in CheckIntrinsicOperator");
+ ok = false;
+ break;
+ }
+ }
+ },
+ [&](const parser::ProcedureDesignator &procD) {
+ const parser::Name *name{std::get_if<parser::Name>(&procD.u)};
+ if (name && name->symbol) {
+ const SourceName &realName{name->symbol->GetUltimate().name()};
+ // OMP5.2: The type [...] of a list item that appears in a
+ // reduction clause must be valid for the combiner expression
+ if (realName == "iand" || realName == "ior" ||
+ realName == "ieor") {
+ // IAND: arguments must be integers: F2023 16.9.100
+ // IEOR: arguments must be integers: F2023 16.9.106
+ // IOR: arguments must be integers: F2023 16.9.111
+ ok = type.IsNumeric(TypeCategory::Integer);
+ } else if (realName == "max" || realName == "min") {
+ // MAX: arguments must be integer, real, or character:
+ // F2023 16.9.135
+ // MIN: arguments must be integer, real, or character:
+ // F2023 16.9.141
+ ok = type.IsNumeric(TypeCategory::Integer) ||
+ type.IsNumeric(TypeCategory::Real) || IsCharacter(type);
+ }
+ }
+ },
+ },
+ definedOp.u);
+
+ return ok;
+}
+
void OmpStructureChecker::CheckReductionTypeList(
const parser::OmpClause::Reduction &x) {
const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
@@ -2397,6 +2478,10 @@ void OmpStructureChecker::CheckReductionTypeList(
context_.Say(source,
"A procedure pointer '%s' must not appear in a REDUCTION clause."_err_en_US,
symbol->name());
+ } else if (!IsReductionAllowedForType(x, DEREF(symbol->GetType()))) {
+ context_.Say(source,
+ "The type of '%s' is incompatible with the reduction operator."_err_en_US,
+ symbol->name());
}
}
}
@@ -2696,7 +2781,7 @@ void OmpStructureChecker::CheckIsLoopIvPartOfClause(
}
}
}
-// Following clauses have a seperate node in parse-tree.h.
+// Following clauses have a separate node in parse-tree.h.
// Atomic-clause
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read)
CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write)
@@ -2802,18 +2887,18 @@ void OmpStructureChecker::CheckAllowedMapTypes(
const parser::OmpMapType::Type &type,
const std::list<parser::OmpMapType::Type> &allowedMapTypeList) {
if (!llvm::is_contained(allowedMapTypeList, type)) {
- std::string commaSeperatedMapTypes;
+ std::string commaSeparatedMapTypes;
llvm::interleave(
allowedMapTypeList.begin(), allowedMapTypeList.end(),
[&](const parser::OmpMapType::Type &mapType) {
- commaSeperatedMapTypes.append(parser::ToUpperCaseLetters(
+ commaSeparatedMapTypes.append(parser::ToUpperCaseLetters(
parser::OmpMapType::EnumToString(mapType)));
},
- [&] { commaSeperatedMapTypes.append(", "); });
+ [&] { commaSeparatedMapTypes.append(", "); });
context_.Say(GetContext().clauseSource,
"Only the %s map types are permitted "
"for MAP clauses on the %s directive"_err_en_US,
- commaSeperatedMapTypes, ContextDirectiveAsFortran());
+ commaSeparatedMapTypes, ContextDirectiveAsFortran());
}
}