Skip to content

Commit

Permalink
Merge pull request #2814 from stfc/2704_backward_accesses
Browse files Browse the repository at this point in the history
2704 backward accesses
  • Loading branch information
sergisiso authored Jan 13, 2025
2 parents b051810 + e8273f0 commit 2307ac7
Show file tree
Hide file tree
Showing 7 changed files with 1,189 additions and 82 deletions.
3 changes: 3 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
10) PR #2810. Adds caching of the fparser2 parse tree to FileInfo. Is
disabled by default.

11) PR #2814 for #2704. Adds backward accesses capabilities to the
DefinitionUseChain tool.

release 3.0.0 6th of December 2024

1) PR #2477 for #2463. Add support for Fortran Namelist statements.
Expand Down
6 changes: 3 additions & 3 deletions doc/developer_guide/dependency.rst
Original file line number Diff line number Diff line change
Expand Up @@ -666,12 +666,12 @@ can be parallelised:
DefinitionUseChain
==================
PSyclone also provides a DefinitionUseChain class, which can search for forward
dependencies (backward NYI) for a given Reference inside a region of code. This
and backward dependencies for a given Reference inside a region of code. This
implementation differs from the DependencyTools as it is control-flow aware, so
can find many dependencies for a single Reference in a given Routine or scope.

This is primarily used to implement the `References.next_accesses` function, but can be
used directly as follows:
This is primarily used to implement the `Reference.next_accesses` and
`Reference.previous_accessess` functions, but can be used directly as follows:

.. code::
Expand Down
34 changes: 9 additions & 25 deletions src/psyclone/psyir/nodes/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
''' This module contains the implementation of the Reference node.'''


from psyclone.core import AccessType, Signature, VariablesAccessInfo
from psyclone.core import AccessType, Signature
# We cannot import from 'nodes' directly due to circular import
from psyclone.psyir.nodes.datanode import DataNode
from psyclone.psyir.symbols import Symbol
Expand Down Expand Up @@ -233,34 +233,18 @@ def datatype(self):
return UnresolvedType()
return self.symbol.datatype

def previous_access(self):
def previous_accesses(self):
'''
:returns: the previous reference to the same symbol.
:rtype: Optional[:py:class:`psyclone.psyir.nodes.Node`]
:returns: the nodes accessing the same symbol directly before this
reference. It can be multiple nodes if the control flow
diverges and there are multiple possible accesses.
:rtype: List[:py:class:`psyclone.psyir.nodes.Node`]
'''
# Avoid circular import
# pylint: disable=import-outside-toplevel
from psyclone.psyir.nodes.routine import Routine
# The scope is as far as the Routine that contains this
# Reference.
routine = self.ancestor(Routine)
# Handle the case when this is a subtree without an ancestor
# Routine
if routine is None:
routine = self.root
var_access = VariablesAccessInfo(nodes=routine)
signature, _ = self.get_signature_and_indices()
all_accesses = var_access[signature].all_accesses
index = -1
# Find my position in the VariablesAccesInfo
for i, access in enumerate(all_accesses):
if access.node is self:
index = i
break

if index > 0:
return all_accesses[index-1].node
return None
from psyclone.psyir.tools import DefinitionUseChain
chain = DefinitionUseChain(self)
return chain.find_backward_accesses()

def next_accesses(self):
'''
Expand Down
442 changes: 422 additions & 20 deletions src/psyclone/psyir/tools/definition_use_chains.py

Large diffs are not rendered by default.

93 changes: 61 additions & 32 deletions src/psyclone/tests/psyir/nodes/reference_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,15 +247,31 @@ def test_reference_next_accesses(fortran_reader):
end subroutine'''
psyir = fortran_reader.psyir_from_source(code)
routine = psyir.children[0]
a = routine.children[0].lhs
a_before_loop = routine.children[0].lhs
loop = routine.children[1]
b = loop.loop_body.children[0].lhs
a_2 = loop.loop_body.children[0].rhs
assert len(a.next_accesses()) == 1
assert a.next_accesses()[0] is loop
assert len(a_before_loop.next_accesses()) == 1
assert a_before_loop.next_accesses()[0] is loop
assert len(b.next_accesses()) == 1
assert b.next_accesses()[0] == b

# Check that a loop accessing a variable before
# the reference doesn't result in a false positive.
code = '''subroutine my_sub()
integer :: a
integer :: b
do a = 0, 10
b = a
end do
a = 1
end subroutine'''
psyir = fortran_reader.psyir_from_source(code)
routine = psyir.children[0]
a_after_loop = routine.children[1].lhs
loop = routine.children[0]
b = loop.loop_body.children[0].lhs
assert len(a_after_loop.next_accesses()) == 0

# Check the function for basic structures
code = '''subroutine my_sub()
type :: x
Expand Down Expand Up @@ -359,8 +375,8 @@ def test_reference_next_accesses_with_codeblock(fortran_reader):
assert a.next_accesses()[0] is codeblock


def test_reference_previous_access(fortran_reader):
'''Test the previous_access function for a Reference'''
def test_reference_previous_accesses(fortran_reader):
'''Test the previous_accesses function for a Reference'''
code = '''subroutine my_sub()
integer :: a
integer :: b
Expand All @@ -374,10 +390,10 @@ def test_reference_previous_access(fortran_reader):
b = routine.children[1].lhs
a_2 = routine.children[2].lhs
b_2 = routine.children[2].rhs
assert a.previous_access() is None
assert b.previous_access() is None
assert a_2.previous_access() is a
assert b_2.previous_access() is b
assert len(a.previous_accesses()) == 0
assert len(b.previous_accesses()) == 0
assert a_2.previous_accesses()[0] is a
assert b_2.previous_accesses()[0] is b

code = '''subroutine my_sub()
integer :: a
Expand All @@ -393,9 +409,11 @@ def test_reference_previous_access(fortran_reader):
loop = routine.children[1]
b_a = loop.loop_body.children[0].lhs
a_2 = loop.loop_body.children[0].rhs
assert a.previous_access() is None
assert b_a.previous_access() is None
assert a_2.previous_access() is loop
assert len(a.previous_accesses()) == 0
assert len(b_a.previous_accesses()) == 1
assert b_a.previous_accesses()[0] is b_a
assert len(a_2.previous_accesses()) == 1
assert a_2.previous_accesses()[0] is loop

# Check the function for basic structures
code = '''subroutine my_sub()
Expand All @@ -415,10 +433,12 @@ def test_reference_previous_access(fortran_reader):
b = routine.children[1].lhs
a_2 = routine.children[2].lhs
b_2 = routine.children[3].lhs
assert a.previous_access() is None
assert b.previous_access() is None
assert a_2.previous_access() is a
assert b_2.previous_access() is b
assert len(a.previous_accesses()) == 0
assert len(b.previous_accesses()) == 0
assert len(a_2.previous_accesses()) == 1
assert len(b_2.previous_accesses()) == 1
assert a_2.previous_accesses()[0] is a
assert b_2.previous_accesses()[0] is b

# Check the function for array access
code = '''subroutine my_sub()
Expand All @@ -430,8 +450,9 @@ def test_reference_previous_access(fortran_reader):
routine = psyir.children[0]
a = routine.children[0].lhs
a_2 = routine.children[1].lhs
assert a.previous_access() is None
assert a_2.previous_access() is a
assert len(a.previous_accesses()) == 0
assert len(a_2.previous_accesses()) == 1
assert a_2.previous_accesses()[0] is a

# Check if statements
code = '''subroutine my_sub()
Expand All @@ -448,9 +469,12 @@ def test_reference_previous_access(fortran_reader):
a = routine.children[0].lhs
a_2 = routine.children[1].if_body.children[0].lhs
a_3 = routine.children[2].lhs
assert a.previous_access() is None
assert a_2.previous_access() is a
assert a_3.previous_access() is a_2
assert len(a.previous_accesses()) == 0
assert len(a_2.previous_accesses()) == 1
assert a_2.previous_accesses()[0] is a
assert len(a_3.previous_accesses()) == 2
assert a_3.previous_accesses()[0] is a_2
assert a_3.previous_accesses()[1] is a

# Check else block behaviour
code = '''subroutine my_sub()
Expand All @@ -470,10 +494,15 @@ def test_reference_previous_access(fortran_reader):
a_2 = routine.children[1].if_body.children[0].lhs
a_3 = routine.children[1].else_body.children[0].lhs
a_4 = routine.children[2].lhs
assert a.previous_access() is None
assert a_2.previous_access() is a
assert a_3.previous_access() is a_2
assert a_4.previous_access() is a_3
assert len(a.previous_accesses()) == 0
assert len(a_2.previous_accesses()) == 1
assert a_2.previous_accesses()[0] is a
assert len(a_2.previous_accesses()) == 1
assert a_3.previous_accesses()[0] is a
assert len(a_4.previous_accesses()) == 3
assert a_4.previous_accesses()[0] is a_3
assert a_4.previous_accesses()[1] is a_2
assert a_4.previous_accesses()[2] is a


def test_reference_accesses_initialisation_statement(fortran_reader):
Expand All @@ -492,20 +521,20 @@ def test_reference_accesses_initialisation_statement(fortran_reader):
psyir = fortran_reader.psyir_from_source(code)
routine = psyir.children[0].children[0]
a = routine.children[0].lhs
assert a.previous_access() is None
assert len(a.previous_accesses()) == 0

sym_tab = routine.symbol_table
symbols = sym_tab.get_symbols()
b_sym = symbols['b']
refs = b_sym.initial_value.walk(Reference)
assert refs[0].next_accesses()[0] == refs[1]
assert refs[1].previous_access() == refs[0]
assert refs[0].previous_access() is None
assert refs[1].previous_accesses()[0] == refs[0]
assert len(refs[0].previous_accesses()) == 0
assert len(refs[1].next_accesses()) == 0


def test_reference_previous_access_with_codeblock(fortran_reader):
''' Test when te previous_access is a Codeblock. '''
def test_reference_previous_accesses_with_codeblock(fortran_reader):
''' Test when te previous_accesses is a Codeblock. '''
code = '''subroutine my_sub()
character, dimension(100) :: a
write(a, "A") "mytest"
Expand All @@ -516,7 +545,7 @@ def test_reference_previous_access_with_codeblock(fortran_reader):
routine = psyir.children[0]
a = routine.children[1].lhs
codeblock = routine.children[1]
if a.previous_access() is not codeblock:
if a.previous_accesses() is not codeblock:
pytest.xfail("#2271 Codeblocks don't currently support "
"reference_accesses")

Expand Down
Loading

0 comments on commit 2307ac7

Please sign in to comment.