Skip to content

Commit c2d5ec6

Browse files
committed
[flang][OpenMP] Implement CheckReductionObjects for all reduction clauses
Currently we only do semantic checks for REDUCTION. There are two other clauses, IN_REDUCTION, and TASK_REDUCTION which will also need those checks. Implement a function that checks the common requirements for all those clauses.
1 parent 9c5217c commit c2d5ec6

File tree

7 files changed

+181
-94
lines changed

7 files changed

+181
-94
lines changed

flang/lib/Semantics/check-omp-structure.cpp

Lines changed: 164 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,30 @@ std::string TryVersion(unsigned version) {
5151
return "try -fopenmp-version=" + std::to_string(version);
5252
}
5353

54+
static const parser::Designator *GetDesignatorFromObj(
55+
const parser::OmpObject &object) {
56+
return std::get_if<parser::Designator>(&object.u);
57+
}
58+
59+
static const parser::DataRef *GetDataRefFromObj(
60+
const parser::OmpObject &object) {
61+
if (auto *desg{GetDesignatorFromObj(object)}) {
62+
return std::get_if<parser::DataRef>(&desg->u);
63+
}
64+
return nullptr;
65+
}
66+
67+
static const parser::ArrayElement *GetArrayElementFromObj(
68+
const parser::OmpObject &object) {
69+
if (auto *dataRef{GetDataRefFromObj(object)}) {
70+
using ElementIndirection = common::Indirection<parser::ArrayElement>;
71+
if (auto *ind{std::get_if<ElementIndirection>(&dataRef->u)}) {
72+
return &ind->value();
73+
}
74+
}
75+
return nullptr;
76+
}
77+
5478
// 'OmpWorkshareBlockChecker' is used to check the validity of the assignment
5579
// statements and the expressions enclosed in an OpenMP Workshare construct
5680
class OmpWorkshareBlockChecker {
@@ -222,6 +246,10 @@ bool OmpStructureChecker::CheckAllowedClause(llvmOmpClause clause) {
222246
return CheckAllowed(clause);
223247
}
224248

249+
bool OmpStructureChecker::IsCommonBlock(const Symbol &sym) {
250+
return sym.detailsIf<CommonBlockDetails>() != nullptr;
251+
}
252+
225253
bool OmpStructureChecker::IsVariableListItem(const Symbol &sym) {
226254
return evaluate::IsVariable(sym) || sym.attrs().test(Attr::POINTER);
227255
}
@@ -2895,6 +2923,8 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
28952923
CheckReductionModifier(*maybeModifier);
28962924
}
28972925
}
2926+
CheckReductionObjects(std::get<parser::OmpObjectList>(x.v.t),
2927+
llvm::omp::Clause::OMPC_reduction);
28982928
}
28992929

29002930
bool OmpStructureChecker::CheckReductionOperators(
@@ -2963,6 +2993,69 @@ bool OmpStructureChecker::CheckIntrinsicOperator(
29632993
return false;
29642994
}
29652995

2996+
/// Check restrictions on objects that are common to all reduction clauses.
2997+
void OmpStructureChecker::CheckReductionObjects(
2998+
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId) {
2999+
unsigned version{context_.langOptions().OpenMPVersion};
3000+
SymbolSourceMap symbols;
3001+
GetSymbolsInObjectList(objects, symbols);
3002+
3003+
// Array sections must be a contiguous storage, have non-zero length.
3004+
for (const parser::OmpObject &object : objects.v) {
3005+
CheckIfContiguous(object);
3006+
}
3007+
CheckReductionArraySection(objects);
3008+
// An object must be definable.
3009+
CheckDefinableObjects(symbols, clauseId);
3010+
// Procedure pointers are not allowed.
3011+
CheckProcedurePointer(symbols, clauseId);
3012+
// Pointers must not have INTENT(IN).
3013+
CheckIntentInPointer(symbols, clauseId);
3014+
3015+
// Disallow common blocks.
3016+
// Iterate on objects because `GetSymbolsInObjectList` expands common block
3017+
// names into the lists of their members.
3018+
for (const parser::OmpObject &object : objects.v) {
3019+
auto *symbol{GetObjectSymbol(object)};
3020+
assert(symbol && "Expecting a symbol for object");
3021+
if (IsCommonBlock(*symbol)) {
3022+
auto source{GetObjectSource(object)};
3023+
context_.Say(source ? *source : GetContext().clauseSource,
3024+
"Common block names are not allowed in %s clause"_err_en_US,
3025+
parser::ToUpperCaseLetters(getClauseName(clauseId).str()));
3026+
}
3027+
}
3028+
3029+
if (version >= 50) {
3030+
// Object cannot be a part of another object (except array elements)
3031+
CheckStructureComponent(objects, clauseId);
3032+
// If object is an array section or element, the base expression must be
3033+
// a language identifier.
3034+
for (const parser::OmpObject &object : objects.v) {
3035+
if (auto *elem{GetArrayElementFromObj(object)}) {
3036+
const parser::DataRef &base = elem->base;
3037+
if (!std::holds_alternative<parser::Name>(base.u)) {
3038+
auto source{GetObjectSource(object)};
3039+
context_.Say(source ? *source : GetContext().clauseSource,
3040+
"The base expression of an array element in %s clause must be an identifier"_err_en_US,
3041+
parser::ToUpperCaseLetters(getClauseName(clauseId).str()));
3042+
}
3043+
}
3044+
}
3045+
// Type parameter inquiries are not allowed.
3046+
for (const parser::OmpObject &object : objects.v) {
3047+
if (auto *dataRef{GetDataRefFromObj(object)}) {
3048+
if (IsDataRefTypeParamInquiry(dataRef)) {
3049+
auto source{GetObjectSource(object)};
3050+
context_.Say(source ? *source : GetContext().clauseSource,
3051+
"Type parameter inquiry is not permitted in %s clause"_err_en_US,
3052+
parser::ToUpperCaseLetters(getClauseName(clauseId).str()));
3053+
}
3054+
}
3055+
}
3056+
}
3057+
}
3058+
29663059
static bool IsReductionAllowedForType(
29673060
const parser::OmpClause::Reduction &x, const DeclTypeSpec &type) {
29683061
auto &modifiers{OmpGetModifiers(x.v)};
@@ -3052,26 +3145,25 @@ static bool IsReductionAllowedForType(
30523145
void OmpStructureChecker::CheckReductionTypeList(
30533146
const parser::OmpClause::Reduction &x) {
30543147
const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
3055-
CheckIntentInPointerAndDefinable(
3056-
ompObjectList, llvm::omp::Clause::OMPC_reduction);
3148+
SymbolSourceMap symbols;
3149+
GetSymbolsInObjectList(ompObjectList, symbols);
3150+
30573151
CheckReductionArraySection(ompObjectList);
30583152
// If this is a worksharing construct then ensure the reduction variable
30593153
// is not private in the parallel region that it binds to.
30603154
if (llvm::omp::nestedReduceWorkshareAllowedSet.test(GetContext().directive)) {
30613155
CheckSharedBindingInOuterContext(ompObjectList);
30623156
}
30633157

3064-
SymbolSourceMap symbols;
3065-
GetSymbolsInObjectList(ompObjectList, symbols);
30663158
for (auto &[symbol, source] : symbols) {
3067-
if (IsProcedurePointer(*symbol)) {
3068-
context_.Say(source,
3069-
"A procedure pointer '%s' must not appear in a REDUCTION clause."_err_en_US,
3070-
symbol->name());
3071-
} else if (!IsReductionAllowedForType(x, DEREF(symbol->GetType()))) {
3072-
context_.Say(source,
3073-
"The type of '%s' is incompatible with the reduction operator."_err_en_US,
3074-
symbol->name());
3159+
if (auto *type{symbol->GetType()}) {
3160+
if (!IsReductionAllowedForType(x, *type)) {
3161+
context_.Say(source,
3162+
"The type of '%s' is incompatible with the reduction operator."_err_en_US,
3163+
symbol->name());
3164+
}
3165+
} else {
3166+
assert(IsProcedurePointer(*symbol) && "Unexpected symbol properties");
30753167
}
30763168
}
30773169
}
@@ -3127,43 +3219,14 @@ void OmpStructureChecker::CheckReductionModifier(
31273219
}
31283220
}
31293221

3130-
void OmpStructureChecker::CheckIntentInPointerAndDefinable(
3131-
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
3132-
for (const auto &ompObject : objectList.v) {
3133-
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
3134-
if (const auto *symbol{name->symbol}) {
3135-
if (IsPointer(symbol->GetUltimate()) &&
3136-
IsIntentIn(symbol->GetUltimate())) {
3137-
context_.Say(GetContext().clauseSource,
3138-
"Pointer '%s' with the INTENT(IN) attribute may not appear "
3139-
"in a %s clause"_err_en_US,
3140-
symbol->name(),
3141-
parser::ToUpperCaseLetters(getClauseName(clause).str()));
3142-
} else if (auto msg{WhyNotDefinable(name->source,
3143-
context_.FindScope(name->source), DefinabilityFlags{},
3144-
*symbol)}) {
3145-
context_
3146-
.Say(GetContext().clauseSource,
3147-
"Variable '%s' on the %s clause is not definable"_err_en_US,
3148-
symbol->name(),
3149-
parser::ToUpperCaseLetters(getClauseName(clause).str()))
3150-
.Attach(std::move(msg->set_severity(parser::Severity::Because)));
3151-
}
3152-
}
3153-
}
3154-
}
3155-
}
3156-
31573222
void OmpStructureChecker::CheckReductionArraySection(
31583223
const parser::OmpObjectList &ompObjectList) {
31593224
for (const auto &ompObject : ompObjectList.v) {
31603225
if (const auto *dataRef{parser::Unwrap<parser::DataRef>(ompObject)}) {
31613226
if (const auto *arrayElement{
31623227
parser::Unwrap<parser::ArrayElement>(ompObject)}) {
3163-
if (arrayElement) {
3164-
CheckArraySection(*arrayElement, GetLastName(*dataRef),
3165-
llvm::omp::Clause::OMPC_reduction);
3166-
}
3228+
CheckArraySection(*arrayElement, GetLastName(*dataRef),
3229+
llvm::omp::Clause::OMPC_reduction);
31673230
}
31683231
}
31693232
}
@@ -3232,9 +3295,11 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Shared &x) {
32323295
CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v, "SHARED");
32333296
}
32343297
void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) {
3298+
SymbolSourceMap symbols;
3299+
GetSymbolsInObjectList(x.v, symbols);
32353300
CheckAllowedClause(llvm::omp::Clause::OMPC_private);
32363301
CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v, "PRIVATE");
3237-
CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_private);
3302+
CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_private);
32383303
}
32393304

32403305
void OmpStructureChecker::Enter(const parser::OmpClause::Nowait &x) {
@@ -3891,11 +3956,11 @@ void OmpStructureChecker::CheckCopyingPolymorphicAllocatable(
38913956

38923957
void OmpStructureChecker::Enter(const parser::OmpClause::Copyprivate &x) {
38933958
CheckAllowedClause(llvm::omp::Clause::OMPC_copyprivate);
3894-
CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_copyprivate);
3895-
SymbolSourceMap currSymbols;
3896-
GetSymbolsInObjectList(x.v, currSymbols);
3959+
SymbolSourceMap symbols;
3960+
GetSymbolsInObjectList(x.v, symbols);
3961+
CheckIntentInPointer(symbols, llvm::omp::Clause::OMPC_copyprivate);
38973962
CheckCopyingPolymorphicAllocatable(
3898-
currSymbols, llvm::omp::Clause::OMPC_copyprivate);
3963+
symbols, llvm::omp::Clause::OMPC_copyprivate);
38993964
if (GetContext().directive == llvm::omp::Directive::OMPD_single) {
39003965
context_.Say(GetContext().clauseSource,
39013966
"%s clause is not allowed on the OMP %s directive,"
@@ -3945,29 +4010,26 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Copyin &x) {
39454010
currSymbols, llvm::omp::Clause::OMPC_copyin);
39464011
}
39474012

3948-
void OmpStructureChecker::CheckStructureElement(
3949-
const parser::OmpObjectList &ompObjectList,
3950-
const llvm::omp::Clause clause) {
3951-
for (const auto &ompObject : ompObjectList.v) {
4013+
void OmpStructureChecker::CheckStructureComponent(
4014+
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId) {
4015+
auto CheckComponent{[&](const parser::Designator &designator) {
4016+
if (auto *desg{std::get_if<parser::DataRef>(&designator.u)}) {
4017+
if (auto *comp{parser::Unwrap<parser::StructureComponent>(*desg)}) {
4018+
context_.Say(comp->component.source,
4019+
"A variable that is part of another variable cannot appear on the %s clause"_err_en_US,
4020+
parser::ToUpperCaseLetters(getClauseName(clauseId).str()));
4021+
}
4022+
}
4023+
}};
4024+
4025+
for (const auto &object : objects.v) {
39524026
common::visit(
39534027
common::visitors{
3954-
[&](const parser::Designator &designator) {
3955-
if (std::get_if<parser::DataRef>(&designator.u)) {
3956-
if (parser::Unwrap<parser::StructureComponent>(ompObject)) {
3957-
context_.Say(GetContext().clauseSource,
3958-
"A variable that is part of another variable "
3959-
"(structure element) cannot appear on the %s "
3960-
"%s clause"_err_en_US,
3961-
ContextDirectiveAsFortran(),
3962-
parser::ToUpperCaseLetters(getClauseName(clause).str()));
3963-
}
3964-
}
3965-
},
4028+
CheckComponent,
39664029
[&](const parser::Name &name) {},
39674030
},
3968-
ompObject.u);
4031+
object.u);
39694032
}
3970-
return;
39714033
}
39724034

39734035
void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
@@ -4009,7 +4071,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Update &x) {
40094071
}
40104072

40114073
void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
4012-
CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_ptr);
4074+
CheckStructureComponent(x.v, llvm::omp::Clause::OMPC_use_device_ptr);
40134075
CheckAllowedClause(llvm::omp::Clause::OMPC_use_device_ptr);
40144076
SymbolSourceMap currSymbols;
40154077
GetSymbolsInObjectList(x.v, currSymbols);
@@ -4038,7 +4100,7 @@ void OmpStructureChecker::Enter(const parser::OmpClause::UseDevicePtr &x) {
40384100
}
40394101

40404102
void OmpStructureChecker::Enter(const parser::OmpClause::UseDeviceAddr &x) {
4041-
CheckStructureElement(x.v, llvm::omp::Clause::OMPC_use_device_addr);
4103+
CheckStructureComponent(x.v, llvm::omp::Clause::OMPC_use_device_addr);
40424104
CheckAllowedClause(llvm::omp::Clause::OMPC_use_device_addr);
40434105
SymbolSourceMap currSymbols;
40444106
GetSymbolsInObjectList(x.v, currSymbols);
@@ -4214,6 +4276,26 @@ llvm::StringRef OmpStructureChecker::getDirectiveName(
42144276
return llvm::omp::getOpenMPDirectiveName(directive);
42154277
}
42164278

4279+
const Symbol *OmpStructureChecker::GetObjectSymbol(
4280+
const parser::OmpObject &object) {
4281+
if (auto *name{std::get_if<parser::Name>(&object.u)}) {
4282+
return &name->symbol->GetUltimate();
4283+
} else if (auto *desg{std::get_if<parser::Designator>(&object.u)}) {
4284+
return &GetLastName(*desg).symbol->GetUltimate();
4285+
}
4286+
return nullptr;
4287+
}
4288+
4289+
std::optional<parser::CharBlock> OmpStructureChecker::GetObjectSource(
4290+
const parser::OmpObject &object) {
4291+
if (auto *name{std::get_if<parser::Name>(&object.u)}) {
4292+
return name->source;
4293+
} else if (auto *desg{std::get_if<parser::Designator>(&object.u)}) {
4294+
return GetLastName(*desg).source;
4295+
}
4296+
return std::nullopt;
4297+
}
4298+
42174299
void OmpStructureChecker::CheckDependList(const parser::DataRef &d) {
42184300
common::visit(
42194301
common::visitors{
@@ -4267,15 +4349,6 @@ void OmpStructureChecker::CheckArraySection(
42674349
"DEPEND "
42684350
"clause"_err_en_US);
42694351
}
4270-
const auto stride{GetIntValue(strideExpr)};
4271-
if ((stride && stride != 1)) {
4272-
context_.Say(GetContext().clauseSource,
4273-
"A list item that appears in a REDUCTION clause"
4274-
" should have a contiguous storage array "
4275-
"section."_err_en_US,
4276-
ContextDirectiveAsFortran());
4277-
break;
4278-
}
42794352
}
42804353
}
42814354
}
@@ -4286,14 +4359,23 @@ void OmpStructureChecker::CheckArraySection(
42864359
}
42874360

42884361
void OmpStructureChecker::CheckIntentInPointer(
4289-
const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) {
4290-
SymbolSourceMap symbols;
4291-
GetSymbolsInObjectList(objectList, symbols);
4362+
SymbolSourceMap &symbols, llvm::omp::Clause clauseId) {
42924363
for (auto &[symbol, source] : symbols) {
42934364
if (IsPointer(*symbol) && IsIntentIn(*symbol)) {
42944365
context_.Say(source,
4295-
"Pointer '%s' with the INTENT(IN) attribute may not appear "
4296-
"in a %s clause"_err_en_US,
4366+
"Pointer '%s' with the INTENT(IN) attribute may not appear in a %s clause"_err_en_US,
4367+
symbol->name(),
4368+
parser::ToUpperCaseLetters(getClauseName(clauseId).str()));
4369+
}
4370+
}
4371+
}
4372+
4373+
void OmpStructureChecker::CheckProcedurePointer(
4374+
SymbolSourceMap &symbols, llvm::omp::Clause clause) {
4375+
for (const auto &[symbol, source] : symbols) {
4376+
if (IsProcedurePointer(*symbol)) {
4377+
context_.Say(source,
4378+
"Procedure pointer '%s' may not appear in a %s clause"_err_en_US,
42974379
symbol->name(),
42984380
parser::ToUpperCaseLetters(getClauseName(clause).str()));
42994381
}

0 commit comments

Comments
 (0)