Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(Towards 2421) Suggested fix to inline trans #2430

Merged
merged 7 commits into from
Dec 12, 2023
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
17 changes: 14 additions & 3 deletions src/psyclone/psyir/transformations/inline_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ def apply(self, node, options=None):

'''
self.validate(node, options)

# The table associated with the scoping region holding the Call.
table = node.scope.symbol_table
# Find the routine to be inlined.
Expand Down Expand Up @@ -160,7 +159,6 @@ def apply(self, node, options=None):
# Shallow copy the symbols from the routine into the table at the
# call site.
table.merge(routine_table, include_arguments=False)

# When constructing new references to replace references to formal
# args, we need to know whether any of the actual arguments are array
# accesses. If they use 'array notation' (i.e. represent a whole array)
Expand All @@ -181,6 +179,10 @@ def apply(self, node, options=None):
for ref in refs[:]:
self._replace_formal_arg(ref, node, formal_args)

# Store the Routine level symbol table and node's current scope
# so we can merge symbol tables later if required.
ancestor_table = node.ancestor(Routine).scope.symbol_table
scope = node.scope
# Copy the nodes from the Routine into the call site.
if isinstance(new_stmts[-1], Return):
# If the final statement of the routine is a return then
Expand Down Expand Up @@ -210,6 +212,16 @@ def apply(self, node, options=None):
idx += 1
parent.addchild(child, idx)

# If the scope we merged the inlined functions symbol table into
# is not a Routine scope then we now merge that symbol table into
# the ancestor Routine. This avoids issues like #2424 when
# applying ParallelLoopTrans to loops containing inlined calls.
if ancestor_table is not scope.symbol_table:
ancestor_table.merge(scope.symbol_table)
replacement = type(scope.symbol_table)()
scope.symbol_table.detach()
replacement.attach(scope)

def _replace_formal_arg(self, ref, call_node, formal_args):
'''
Recursively combines any References to formal arguments in the supplied
Expand Down Expand Up @@ -596,7 +608,6 @@ def validate(self, node, options=None):
raise TransformationError(
f"Cannot inline an IntrinsicCall ('{node.routine.name}')")
name = node.routine.name

# Check that we can find the source of the routine being inlined.
routine = self._find_routine(node)

Expand Down
52 changes: 42 additions & 10 deletions src/psyclone/tests/psyir/transformations/inline_trans_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -324,20 +324,20 @@ def test_apply_struct_arg(fortran_reader, fortran_writer, tmpdir):

output = fortran_writer(psyir)
assert (" do i = 1, 5, 1\n"
" do i_3 = 1, 10, 1\n"
" var%data(i_3) = 2.0 * i\n"
" do i_1 = 1, 10, 1\n"
" var%data(i_1) = 2.0 * i\n"
" enddo\n"
" var%data(:) = -1.0\n"
" var%data = -5.0\n"
" var%data(1:2) = 0.0\n"
" do i_1 = 1, 10, 1\n"
" var_list(i)%data(i_1) = 2.0 * i\n"
" do i_2 = 1, 10, 1\n"
" var_list(i)%data(i_2) = 2.0 * i\n"
" enddo\n"
" var_list(i)%data(:) = -1.0\n"
" var_list(i)%data = -5.0\n"
" var_list(i)%data(1:2) = 0.0\n"
" do i_2 = 1, 10, 1\n"
" var2(i)%region%data(i_2) = 2.0 * i\n"
" do i_3 = 1, 10, 1\n"
" var2(i)%region%data(i_3) = 2.0 * i\n"
" enddo\n"
" var2(i)%region%data(:) = -1.0\n"
" var2(i)%region%data = -5.0\n"
Expand Down Expand Up @@ -719,15 +719,15 @@ def test_apply_array_slice_arg(fortran_reader, fortran_writer, tmpdir):
inline_trans.apply(call)
output = fortran_writer(psyir)
assert (" do i = 1, 10, 1\n"
arporter marked this conversation as resolved.
Show resolved Hide resolved
" do i_4 = 1, 10, 1\n"
" a(1,i_4,i) = 2.0 * i_4\n"
" do i_1 = 1, 10, 1\n"
" a(1,i_1,i) = 2.0 * i_1\n"
" enddo\n"
" enddo\n"
" a(1,1,:) = 3.0 * a(1,1,:)\n"
" a(:,1,:) = 2.0 * a(:,1,:)\n"
" b(:,:) = 2.0 * b(:,:)\n"
" do i_3 = 1, 10, 1\n"
" b(i_3,:5) = 2.0 * b(i_3,:5)\n" in output)
" do i_4 = 1, 10, 1\n"
" b(i_4,:5) = 2.0 * b(i_4,:5)\n" in output)
assert Compile(tmpdir).string_compiles(output)


Expand Down Expand Up @@ -2405,3 +2405,35 @@ def test_find_routine_in_container(fortran_reader):
call_node, call_node.routine.interface.container_symbol)
assert isinstance(result, Routine)
assert result.name == "sub"


def test_apply_merges_symbol_table_with_routine(fortran_reader):
'''
Check that the apply method merges the inlined function's symbol table to
the containing Routine when the call node is inside a child ScopingNode.
'''
code = (
"module test_mod\n"
"contains\n"
" subroutine run_it()\n"
" integer :: i\n"
" real :: a(10)\n"
" do i=1,10\n"
" call sub(a, i)\n"
" end do\n"
" end subroutine run_it\n"
" subroutine sub(x, ivar)\n"
" real, intent(inout), dimension(10) :: x\n"
" integer, intent(in) :: ivar\n"
" integer :: i\n"
" do i = 1, 10\n"
" x(i) = 2.0*ivar\n"
" end do\n"
" end subroutine sub\n"
"end module test_mod\n")
psyir = fortran_reader.psyir_from_source(code)
routine = psyir.walk(Call)[0]
inline_trans = InlineTrans()
inline_trans.apply(routine)
# The i_1 symbol is the renamed i from the inlined call.
assert psyir.walk(Routine)[0].symbol_table.get_symbols()['i_1'] is not None
Loading