Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
31) PR #3442. Extends Call.get_callee() to permit implicit reshaping
of arguments.

30) PR #3451 towards #3449. Adds support for keeping 'ACC routine' and
'OMP declare target' directives in existing code.

Expand Down
22 changes: 19 additions & 3 deletions src/psyclone/psyir/nodes/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -703,7 +703,10 @@ def _check_argument_type_matches(
) -> None:
"""Checks whether the supplied call and routine arguments are
compatible. This also supports 'optional' arguments by using
partial types.
partial types. Array arguments are only required to have the same
rank if we are dealing with an interface call (polymorphism) or
the dummy argument does not have an explicit shape (in which
case Fortran permits implicit reshaping).

:param call_arg: One argument of the call
:param routine_arg: One argument of the routine
Expand All @@ -726,8 +729,21 @@ def type_symbols_match(type1: Union[DataTypeSymbol, DataType],
dummy_type = routine_arg.datatype
if isinstance(actual_type, ArrayType) and isinstance(dummy_type,
ArrayType):
# Arguments must have the same shape.
if len(actual_type.shape) != len(dummy_type.shape):
# Is the dummy argument an explicit-shape array?
has_explicit_shape = all([
isinstance(dim, ArrayType.ArrayBounds) and
dim.lower is not ArrayType.Extent.ATTRIBUTE and
dim.upper is not ArrayType.Extent.ATTRIBUTE
for dim in dummy_type.shape])
# Arguments are only required to have the same rank if we are
# dealing with an interface call (polymorphism) or the dummy
# argument does not have an explicit shape (in which case
# Fortran permits implicit reshaping)
match_rank = (isinstance(self.routine.symbol,
GenericInterfaceSymbol) or
not has_explicit_shape)
# Check that ranks of arguments match, if necessary
if match_rank and len(actual_type.shape) != len(dummy_type.shape):
call_arg_str = call_arg.debug_string().strip()
routine_arg_str = routine_arg.name
raise CallMatchingArgumentsNotFound(
Expand Down
72 changes: 67 additions & 5 deletions src/psyclone/tests/psyir/nodes/call_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -1435,6 +1435,62 @@ def test_call_get_callee_8_arguments_not_handled(fortran_reader):
assert "No matching routine found for 'call foo(e, f)" in str(err.value)


def test_call_get_callee_9_implicit_reshaping(fortran_reader):
'''
Check that implicit reshaping of array arguments is permitted
when the dummy argument is an explicit-shape array, provided
that the call is not a call to an interface.
'''
code = '''
module implicit_reshaping_test
implicit none

interface ifc
module procedure sub1
end interface
contains
subroutine top(n)
integer, intent(in) :: n
real :: mat(n, n)
call ifc(mat)
call sub1(mat)
call sub2(mat)
end subroutine

subroutine sub1(arr)
real, intent(in) :: arr(100)
print *, "Called sub1"
end subroutine

subroutine sub2(arr)
real, intent(in) :: arr(1:)
print *, "Called sub2"
end subroutine
end module
'''
psyir: Node = fortran_reader.psyir_from_source(code)
routine_top: Routine = psyir.walk(Routine)[0]
assert routine_top.name == "top"

# Call to 'ifc' should not permit implicit reshaping
call_ifc: Call = routine_top.walk(Call)[0]
with pytest.raises(CallMatchingArgumentsNotFound) as err:
call_ifc.get_callee()
assert "No matching routine found for" in str(err.value)

# Call to 'sub1' should permit implicit reshaping
call_sub1: Call = routine_top.walk(Call)[1]
(result, _) = call_sub1.get_callee()
sub1_match: Routine = psyir.walk(Routine)[1]
assert result is sub1_match

# Call to 'sub2' should not permit implicit reshaping
call_sub2: Call = routine_top.walk(Call)[2]
with pytest.raises(CallMatchingArgumentsNotFound) as err:
call_sub2.get_callee()
assert "No matching routine found for" in str(err.value)


@pytest.mark.usefixtures("clear_module_manager_instance")
def test_call_get_callees_unresolved(fortran_reader, tmpdir, monkeypatch,
config_instance):
Expand Down Expand Up @@ -1915,12 +1971,15 @@ def test_check_argument_type_matches(fortran_reader):
call2._check_argument_type_matches(
call2.arguments[0],
DataSymbol("dummy1", ArrayType(ScalarType.real_type(), shape=[10])))
# Array of wrong rank.
# Array of wrong rank. Implicit reshaping is not permitted because
# the dummy argument is not an explicit-shape array.
with pytest.raises(CallMatchingArgumentsNotFound) as err:
call2._check_argument_type_matches(
call2.arguments[0],
DataSymbol("dummy1", ArrayType(ScalarType.real_type(),
shape=[10, 10])))
DataSymbol("dummy1",
ArrayType(ScalarType.real_type(),
shape=[ArrayType.Extent.ATTRIBUTE,
ArrayType.Extent.ATTRIBUTE])))
assert ("Rank mismatch of call argument 'var2' (rank 1) and routine "
"argument 'dummy1' (rank 2)" in str(err.value))
# Array of wrong intrinsic type.
Expand Down Expand Up @@ -1961,13 +2020,16 @@ def test_check_argument_type_matches(fortran_reader):
assert ("Argument type mismatch of call argument 'athing' (Array<my_type: "
"DataTypeSymbol, shape=[5]>) and routine argument 'dummy1' "
"(MY_type: DataTypeSymbol)" in str(err.value))
# Doesn't match with array of derived type with wrong rank.
# Doesn't match with array of derived type with wrong rank. Implicit
# reshaping is not permitted because the dummy argument is not an
# explicit-shape array.
with pytest.raises(CallMatchingArgumentsNotFound) as err:
call4._check_argument_type_matches(
call4.arguments[0],
DataSymbol("dummy1",
ArrayType(DataTypeSymbol("MY_type", UnresolvedType()),
shape=[3, 4])))
shape=[ArrayType.Extent.ATTRIBUTE,
ArrayType.Extent.ATTRIBUTE])))
assert ("Rank mismatch of call argument 'athing' (rank 1) and routine "
"argument 'dummy1' (rank 2)" in str(err.value))
# Doesn't match with array of a different derived type.
Expand Down
8 changes: 4 additions & 4 deletions src/psyclone/tests/psyir/transformations/inline_trans_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -2213,10 +2213,10 @@ def test_validate_array_reshape(fortran_reader):
inline_trans = InlineTrans()
with pytest.raises(TransformationError) as err:
inline_trans.validate(call)
assert ("Cannot inline routine 's' because the target of the call cannot "
"be found:" in str(err.value))
assert ("Rank mismatch of call argument 'a(:,:)' (rank 2) and routine "
"argument 'x' (rank 1)" in str(err.value))
assert ("Cannot inline routine 's' because it reshapes an argument"
Comment thread
arporter marked this conversation as resolved.
in str(err.value))
assert ("actual argument 'a(:,:)' has rank 2 but the corresponding "
"formal argument, 'x', has rank 1" in str(err.value))
# Check that _validate_inline_of_call_and_routine_argument_pairs() also
# catches this error. (Necessary in case type-checking has been disabled
# in the call to get_callee().)
Expand Down
Loading