Skip to content

Commit a9b2e31

Browse files
authored
[flang] Define CO_REDUCE intrinsic procedure (llvm#125115)
Define the intrinsic `CO_REDUCE` and add semantic checks. A test was already present but was at `XFAIL`. It has been modified to take new messages into the output.
1 parent 83f8721 commit a9b2e31

File tree

3 files changed

+138
-32
lines changed

3 files changed

+138
-32
lines changed

flang/lib/Evaluate/intrinsics.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1440,6 +1440,17 @@ static const IntrinsicInterface intrinsicSubroutine[]{
14401440
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional,
14411441
common::Intent::InOut}},
14421442
{}, Rank::elemental, IntrinsicClass::collectiveSubroutine},
1443+
{"co_reduce",
1444+
{{"a", AnyData, Rank::known, Optionality::required,
1445+
common::Intent::InOut},
1446+
{"operation", SameType, Rank::reduceOperation},
1447+
{"result_image", AnyInt, Rank::scalar, Optionality::optional,
1448+
common::Intent::In},
1449+
{"stat", AnyInt, Rank::scalar, Optionality::optional,
1450+
common::Intent::Out},
1451+
{"errmsg", DefaultChar, Rank::scalar, Optionality::optional,
1452+
common::Intent::InOut}},
1453+
{}, Rank::elemental, IntrinsicClass::collectiveSubroutine},
14431454
{"co_sum",
14441455
{{"a", AnyNumeric, Rank::anyOrAssumedRank, Optionality::required,
14451456
common::Intent::InOut},
@@ -1598,8 +1609,6 @@ static const IntrinsicInterface intrinsicSubroutine[]{
15981609
{}, Rank::elemental, IntrinsicClass::impureSubroutine},
15991610
};
16001611

1601-
// TODO: Collective intrinsic subroutines: co_reduce
1602-
16031612
// Finds a built-in derived type and returns it as a DynamicType.
16041613
static DynamicType GetBuiltinDerivedType(
16051614
const semantics::Scope *builtinsScope, const char *which) {

flang/lib/Semantics/check-call.cpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1632,6 +1632,99 @@ static void CheckAssociated(evaluate::ActualArguments &arguments,
16321632
}
16331633
}
16341634

1635+
// CO_REDUCE (F'2023 16.9.49)
1636+
static void CheckCoReduce(
1637+
evaluate::ActualArguments &arguments, evaluate::FoldingContext &context) {
1638+
parser::ContextualMessages &messages{context.messages()};
1639+
evaluate::CheckForCoindexedObject(
1640+
context.messages(), arguments[0], "co_reduce", "a");
1641+
evaluate::CheckForCoindexedObject(
1642+
context.messages(), arguments[2], "co_reduce", "stat");
1643+
evaluate::CheckForCoindexedObject(
1644+
context.messages(), arguments[3], "co_reduce", "errmsg");
1645+
1646+
std::optional<evaluate::DynamicType> aType;
1647+
if (const auto &a{arguments[0]}) {
1648+
aType = a->GetType();
1649+
}
1650+
std::optional<characteristics::Procedure> procChars;
1651+
if (const auto &operation{arguments[1]}) {
1652+
if (const auto *expr{operation->UnwrapExpr()}) {
1653+
if (const auto *designator{
1654+
std::get_if<evaluate::ProcedureDesignator>(&expr->u)}) {
1655+
procChars = characteristics::Procedure::Characterize(
1656+
*designator, context, /*emitError=*/true);
1657+
} else if (const auto *ref{
1658+
std::get_if<evaluate::ProcedureRef>(&expr->u)}) {
1659+
procChars = characteristics::Procedure::Characterize(*ref, context);
1660+
}
1661+
}
1662+
}
1663+
1664+
static constexpr characteristics::DummyDataObject::Attrs notAllowedArgAttrs{
1665+
characteristics::DummyDataObject::Attr::Optional,
1666+
characteristics::DummyDataObject::Attr::Allocatable,
1667+
characteristics::DummyDataObject::Attr::Pointer,
1668+
};
1669+
static constexpr characteristics::FunctionResult::Attrs
1670+
notAllowedFuncResAttrs{
1671+
characteristics::FunctionResult::Attr::Allocatable,
1672+
characteristics::FunctionResult::Attr::Pointer,
1673+
};
1674+
const auto *result{
1675+
procChars ? procChars->functionResult->GetTypeAndShape() : nullptr};
1676+
if (!procChars || !procChars->IsPure() ||
1677+
procChars->dummyArguments.size() != 2 || !procChars->functionResult) {
1678+
messages.Say(
1679+
"OPERATION= argument of CO_REDUCE() must be a pure function of two data arguments"_err_en_US);
1680+
} else if (procChars->attrs.test(characteristics::Procedure::Attr::BindC)) {
1681+
messages.Say(
1682+
"A BIND(C) OPERATION= argument of CO_REDUCE() is not supported"_err_en_US);
1683+
} else if (!result || result->Rank() != 0) {
1684+
messages.Say(
1685+
"OPERATION= argument of CO_REDUCE() must be a scalar function"_err_en_US);
1686+
} else if (result->type().IsPolymorphic() ||
1687+
(aType && !aType->IsTkLenCompatibleWith(result->type()))) {
1688+
messages.Say(
1689+
"OPERATION= argument of CO_REDUCE() must have the same type as A="_err_en_US);
1690+
} else if (((procChars->functionResult->attrs & notAllowedFuncResAttrs) !=
1691+
characteristics::FunctionResult::Attrs{}) ||
1692+
procChars->functionResult->GetTypeAndShape()->type().IsPolymorphic()) {
1693+
messages.Say(
1694+
"Result of OPERATION= procedure of CO_REDUCE() must be scalar and neither allocatable, pointer, nor polymorphic"_err_en_US);
1695+
} else {
1696+
const characteristics::DummyDataObject *data[2]{};
1697+
for (int j{0}; j < 2; ++j) {
1698+
const auto &dummy{procChars->dummyArguments.at(j)};
1699+
data[j] = std::get_if<characteristics::DummyDataObject>(&dummy.u);
1700+
}
1701+
if (!data[0] || !data[1]) {
1702+
messages.Say(
1703+
"OPERATION= argument of CO_REDUCE() may not have dummy procedure arguments"_err_en_US);
1704+
} else {
1705+
for (int j{0}; j < 2; ++j) {
1706+
if (((data[j]->attrs & notAllowedArgAttrs) !=
1707+
characteristics::DummyDataObject::Attrs{}) ||
1708+
data[j]->type.Rank() != 0 || data[j]->type.type().IsPolymorphic() ||
1709+
(aType && !data[j]->type.type().IsTkCompatibleWith(*aType))) {
1710+
messages.Say(
1711+
"Arguments of OPERATION= procedure of CO_REDUCE() must be both scalar of the same type as A=, and neither allocatable, pointer, polymorphic, nor optional"_err_en_US);
1712+
break;
1713+
}
1714+
}
1715+
static constexpr characteristics::DummyDataObject::Attrs attrs{
1716+
characteristics::DummyDataObject::Attr::Asynchronous,
1717+
characteristics::DummyDataObject::Attr::Target,
1718+
characteristics::DummyDataObject::Attr::Value,
1719+
};
1720+
if ((data[0]->attrs & attrs) != (data[1]->attrs & attrs)) {
1721+
messages.Say(
1722+
"If either argument of the OPERATION= procedure of CO_REDUCE() has the ASYNCHRONOUS, TARGET, or VALUE attribute, both must have that attribute"_err_en_US);
1723+
}
1724+
}
1725+
}
1726+
}
1727+
16351728
// EVENT_QUERY (F'2023 16.9.82)
16361729
static void CheckEvent_Query(evaluate::ActualArguments &arguments,
16371730
evaluate::FoldingContext &foldingContext) {
@@ -1998,6 +2091,8 @@ static void CheckSpecificIntrinsic(const characteristics::Procedure &proc,
19982091
const Scope *scope, const evaluate::SpecificIntrinsic &intrinsic) {
19992092
if (intrinsic.name == "associated") {
20002093
CheckAssociated(arguments, context, scope);
2094+
} else if (intrinsic.name == "co_reduce") {
2095+
CheckCoReduce(arguments, context.foldingContext());
20012096
} else if (intrinsic.name == "event_query") {
20022097
CheckEvent_Query(arguments, context.foldingContext());
20032098
} else if (intrinsic.name == "image_index") {

flang/test/Semantics/collectives05.f90

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
! RUN: %python %S/test_errors.py %s %flang_fc1
2-
! XFAIL: *
32
! This test checks for semantic errors in co_reduce subroutine calls based on
43
! the co_reduce interface defined in section 16.9.49 of the Fortran 2018 standard.
54
! To Do: add co_reduce to the list of intrinsics
@@ -63,119 +62,122 @@ program main
6362
! executing in multiple images is not.
6463

6564
! argument 'a' cannot be polymorphic
66-
!ERROR: to be determined
65+
!ERROR: No explicit type declared for 'derived_type_op'
6766
call co_reduce(polymorphic, derived_type_op)
6867

6968
! argument 'a' cannot be coindexed
70-
!ERROR: (message to be determined)
69+
!ERROR: 'a' argument to 'co_reduce' may not be a coindexed object
7170
call co_reduce(coindexed[1], int_op)
7271

7372
! argument 'a' is intent(inout)
74-
!ERROR: (message to be determined)
73+
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'a=' is not definable
74+
!ERROR: 'i+1_4' is not a variable or pointer
7575
call co_reduce(i + 1, int_op)
7676

7777
! operation must be a pure function
78-
!ERROR: (message to be determined)
78+
!ERROR: OPERATION= argument of CO_REDUCE() must be a pure function of two data arguments
7979
call co_reduce(i, operation=not_pure)
8080

8181
! operation must have exactly two arguments
82-
!ERROR: (message to be determined)
82+
!ERROR: OPERATION= argument of CO_REDUCE() must be a pure function of two data arguments
8383
call co_reduce(i, too_many_args)
8484

8585
! operation result must be a scalar
86-
!ERROR: (message to be determined)
86+
!ERROR: OPERATION= argument of CO_REDUCE() must be a scalar function
8787
call co_reduce(i, array_result)
8888

8989
! operation result must be non-allocatable
90-
!ERROR: (message to be determined)
90+
!ERROR: Result of OPERATION= procedure of CO_REDUCE() must be scalar and neither allocatable, pointer, nor polymorphic
9191
call co_reduce(i, allocatable_result)
9292

9393
! operation result must be non-pointer
94-
!ERROR: (message to be determined)
94+
!ERROR: Result of OPERATION= procedure of CO_REDUCE() must be scalar and neither allocatable, pointer, nor polymorphic
9595
call co_reduce(i, pointer_result)
9696

9797
! operation's arguments must be scalars
98-
!ERROR: (message to be determined)
98+
!ERROR: Arguments of OPERATION= procedure of CO_REDUCE() must be both scalar of the same type as A=, and neither allocatable, pointer, polymorphic, nor optional
9999
call co_reduce(i, array_args)
100100

101101
! operation arguments must be non-allocatable
102-
!ERROR: (message to be determined)
102+
!ERROR: Arguments of OPERATION= procedure of CO_REDUCE() must be both scalar of the same type as A=, and neither allocatable, pointer, polymorphic, nor optional
103103
call co_reduce(i, allocatable_args)
104104

105105
! operation arguments must be non-pointer
106-
!ERROR: (message to be determined)
106+
!ERROR: Arguments of OPERATION= procedure of CO_REDUCE() must be both scalar of the same type as A=, and neither allocatable, pointer, polymorphic, nor optional
107107
call co_reduce(i, pointer_args)
108108

109109
! operation arguments must be non-polymorphic
110-
!ERROR: (message to be determined)
110+
!ERROR: OPERATION= argument of CO_REDUCE() must have the same type as A=
111111
call co_reduce(i, polymorphic_args)
112112

113113
! operation: type of 'operation' result and arguments must match type of argument 'a'
114-
!ERROR: (message to be determined)
114+
!ERROR: OPERATION= argument of CO_REDUCE() must have the same type as A=
115115
call co_reduce(i, real_op)
116116

117117
! operation: kind type parameter of 'operation' result and arguments must match kind type parameter of argument 'a'
118-
!ERROR: (message to be determined)
118+
!ERROR: OPERATION= argument of CO_REDUCE() must have the same type as A=
119119
call co_reduce(x, double_precision_op)
120120

121121
! arguments must be non-optional
122-
!ERROR: (message to be determined)
122+
!ERROR: Arguments of OPERATION= procedure of CO_REDUCE() must be both scalar of the same type as A=, and neither allocatable, pointer, polymorphic, nor optional
123123
call co_reduce(i, optional_args)
124124

125125
! if one argument is asynchronous, the other must be also
126-
!ERROR: (message to be determined)
126+
!ERROR: If either argument of the OPERATION= procedure of CO_REDUCE() has the ASYNCHRONOUS, TARGET, or VALUE attribute, both must have that attribute
127127
call co_reduce(i, asynchronous_mismatch)
128128

129129
! if one argument is a target, the other must be also
130-
!ERROR: (message to be determined)
130+
!ERROR: If either argument of the OPERATION= procedure of CO_REDUCE() has the ASYNCHRONOUS, TARGET, or VALUE attribute, both must have that attribute
131131
call co_reduce(i, target_mismatch)
132132

133133
! if one argument has the value attribute, the other must have it also
134-
!ERROR: (message to be determined)
134+
!ERROR: If either argument of the OPERATION= procedure of CO_REDUCE() has the ASYNCHRONOUS, TARGET, or VALUE attribute, both must have that attribute
135135
call co_reduce(i, value_mismatch)
136136

137137
! result_image argument must be an integer scalar
138-
!ERROR: to be determined
138+
!ERROR: 'result_image=' argument has unacceptable rank 1
139139
call co_reduce(i, int_op, result_image=integer_array)
140140

141141
! result_image argument must be an integer
142-
!ERROR: to be determined
142+
!ERROR: Actual argument for 'result_image=' has bad type 'LOGICAL(4)'
143143
call co_reduce(i, int_op, result_image=bool)
144144

145145
! stat not allowed to be coindexed
146-
!ERROR: to be determined
146+
!ERROR: 'errmsg' argument to 'co_reduce' may not be a coindexed object
147147
call co_reduce(i, int_op, stat=coindexed[1])
148148

149149
! stat argument must be an integer scalar
150-
!ERROR: to be determined
150+
!ERROR: 'stat=' argument has unacceptable rank 1
151151
call co_reduce(i, int_op, result_image=1, stat=integer_array)
152152

153153
! stat argument has incorrect type
154154
!ERROR: Actual argument for 'stat=' has bad type 'CHARACTER(KIND=1,LEN=1_8)'
155-
call co_reduce(i, int_op, result_image=1, string)
155+
call co_reduce(i, int_op, result_image=1, stat=string)
156156

157157
! stat argument is intent(out)
158-
!ERROR: to be determined
158+
!ERROR: Actual argument associated with INTENT(OUT) dummy argument 'stat=' is not definable
159+
!ERROR: '2_4' is not a variable or pointer
159160
call co_reduce(i, int_op, result_image=1, stat=1+1)
160161

161162
! errmsg argument must not be coindexed
162-
!ERROR: to be determined
163+
!ERROR: No explicit type declared for 'conindexed_string'
163164
call co_reduce(i, int_op, result_image=1, stat=status, errmsg=conindexed_string[1])
164165

165166
! errmsg argument must be a character scalar
166-
!ERROR: to be determined
167+
!ERROR: 'errmsg=' argument has unacceptable rank 1
167168
call co_reduce(i, int_op, result_image=1, stat=status, errmsg=character_array)
168169

169170
! errmsg argument must be a character
170-
!ERROR: to be determined
171+
!ERROR: Actual argument for 'errmsg=' has bad type 'INTEGER(4)'
171172
call co_reduce(i, int_op, result_image=1, stat=status, errmsg=i)
172173

173174
! errmsg argument is intent(inout)
174-
!ERROR: to be determined
175+
!ERROR: Actual argument associated with INTENT(IN OUT) dummy argument 'errmsg=' is not definable
176+
!ERROR: '"literal constant"' is not a variable or pointer
175177
call co_reduce(i, int_op, result_image=1, stat=status, errmsg="literal constant")
176178

177179
! too many arguments to the co_reduce() call
178-
!ERROR: too many actual arguments for intrinsic 'co_reduce'
180+
!ERROR: actual argument #6 without a keyword may not follow an actual argument with a keyword
179181
call co_reduce(i, int_op, result_image=1, stat=status, errmsg=message, 3.4)
180182

181183
! non-existent keyword argument

0 commit comments

Comments
 (0)