Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
38bfc61
Make statement abstract with the new abstract methods
LonelyCat124 Aug 4, 2026
c40ed40
Merged master
LonelyCat124 Aug 17, 2026
68c87c7
Implements next and previous accesses for Statement subclasses
LonelyCat124 Aug 17, 2026
dbf7ec2
linting
LonelyCat124 Aug 17, 2026
2dc8ddc
Fixed linting from master merge
LonelyCat124 Aug 17, 2026
7038029
Merge branch 'master' into 3367_statement_next_access
LonelyCat124 Aug 19, 2026
9610ac8
Fix condition for if_block
LonelyCat124 Aug 19, 2026
974b8cd
Changes towards initial if_block tests
LonelyCat124 Aug 19, 2026
3a2d2eb
Some coverage
LonelyCat124 Aug 21, 2026
0b02f50
linting
LonelyCat124 Aug 21, 2026
95bf12e
Merge branch '3367_statement_next_access' of github.com:stfc/PSyclone…
LonelyCat124 Aug 21, 2026
cc4e975
Fixes and coverage improvements
LonelyCat124 Aug 21, 2026
af187d6
typo
LonelyCat124 Aug 21, 2026
bf51be6
Final coverage
LonelyCat124 Aug 21, 2026
fc7456b
Merge branch 'master' into 3367_statement_next_access
LonelyCat124 Aug 21, 2026
0a2abc7
Merge remote-tracking branch 'origin/master' into 3367_statement_next…
sergisiso Sep 3, 2026
31f1448
Merge branch 'master' into 3367_statement_next_access
LonelyCat124 Sep 4, 2026
0ddc419
Adds a loop test that currently fails
LonelyCat124 Sep 7, 2026
5dc5a83
Initial changes looking at Sergi's comments
LonelyCat124 Sep 7, 2026
0960ea1
Fixes towards Sergi's comments
LonelyCat124 Sep 7, 2026
e298743
Changes towards new style, many FIXMEs remain
LonelyCat124 Sep 7, 2026
a260c9a
Fixes non-performance FIXMEs and coverage
LonelyCat124 Sep 8, 2026
d559694
Test name issue
LonelyCat124 Sep 8, 2026
d1630d7
Fixes remaining FIXMEs
LonelyCat124 Sep 8, 2026
b1390d2
Merge branch 'master' into 3367_statement_next_access
LonelyCat124 Sep 8, 2026
845f5b2
Merge master
LonelyCat124 Sep 15, 2026
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
19 changes: 19 additions & 0 deletions src/psyclone/domain/common/psylayer/global_reduction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
''' This module provides the GlobalReduction base class. '''

import copy
from typing import List

from psyclone.configuration import Config
from psyclone.core import AccessType
Expand Down Expand Up @@ -82,3 +83,21 @@ def args(self) -> list[KernelArgument]:
''':returns: the list of arguments associated with this node. Override
the base method and simply return our argument.'''
return [self._scalar]

def next_accesses(self) -> List[Node]:
'''
next_accesses on base GlobalReduction class just uses the base
Statement implementation, returning an empty list.

:returns: an empty list.
'''
return super().next_accesses()

def previous_accesses(self) -> List[Node]:
'''
previous_accesses on base GlobalReduction class just uses the base
Statement implementation, returning an empty list.

:returns: an empty list.
'''
return super().previous_accesses()
32 changes: 32 additions & 0 deletions src/psyclone/psyGen.py
Original file line number Diff line number Diff line change
Expand Up @@ -739,6 +739,22 @@ def node_str(self, colour=True):
f"type='{self._halo_type}', depth={self._halo_depth}, "
f"check_dirty={self._check_dirty}]")

def next_accesses(self) -> list[Node]:
'''
next_accesses on base HaloExchange class returns an empty list.

:returns: an empty list.
'''
return []

def previous_accesses(self) -> list[Node]:
'''
previous_accesses on base HaloExchange class returns an empty list.

:returns: an empty list.
'''
return []


class Kern(Statement):
'''Base class representing a call to a sub-program unit from within the
Expand Down Expand Up @@ -1131,6 +1147,22 @@ def lower_to_language_level(self):

return super().lower_to_language_level()

def next_accesses(self) -> list[Node]:
'''
next_accesses on base Kern class returns an empty list.

:returns: an empty list.
'''
return []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the existing PSy-layer DA, these lists comprise Kern and HaloExchange nodes (I think, perhaps PSyLoop as well?).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps these methods should just raise NotImplementedError for now and we can think about them in a next step?

@arporter arporter Sep 15, 2026 •

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is the PSyLoop objects that hold information on the depth of halo access and are (currently) responsible for creating HaloExchange objects in the Schedule. I can't remember why it was implemented in that way. Thinking about it now, it feels like something that should be done as a final step in the creation of the initial Schedule of the PSy layer.


def previous_accesses(self) -> list[Node]:
'''
previous_accesses on base Kern class returns an empty list.

:returns: an empty list.
'''
return []


class CodedKern(Kern):
'''
Expand Down
24 changes: 18 additions & 6 deletions src/psyclone/psyir/nodes/assignment.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

''' This module contains the Assignment node implementation.'''

from psyclone.core import VariablesAccessMap, AccessType, Signature
from psyclone.core import VariablesAccessMap, AccessType
from psyclone.errors import InternalError
from psyclone.psyir.nodes.literal import Literal
from psyclone.psyir.nodes.array_reference import ArrayReference
Expand Down Expand Up @@ -213,7 +213,7 @@ def is_literal_assignment(self):
'''
return isinstance(self.rhs, Literal)

def previous_accesses(self) -> dict[Signature, list[Node]]:
def previous_accesses(self) -> list[Node]:
'''
:returns: the nodes containing the previous accesses of the symbols
accessed within this node. It can be multiple nodes for
Expand All @@ -229,9 +229,15 @@ def previous_accesses(self) -> dict[Signature, list[Node]]:
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
chain = DefinitionUseChain(refs)
return chain.find_backward_accesses()

def next_accesses(self) -> dict[Signature, list[Node]]:
accesses = chain.find_backward_accesses()
results = []
for sig in accesses:
for access in accesses[sig]:
if all(x is not access for x in results):
Comment thread
arporter marked this conversation as resolved.
results.append(access)
return results

def next_accesses(self) -> list[Node]:
'''
:returns: the nodes containing the next accesses of the symbols
accessed within this node. It can be multiple nodes for
Expand All @@ -247,4 +253,10 @@ def next_accesses(self) -> dict[Signature, list[Node]]:
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
chain = DefinitionUseChain(refs)
return chain.find_forward_accesses()
accesses = chain.find_forward_accesses()
results = []
for sig in accesses:
for access in accesses[sig]:
if all(x is not access for x in results):
results.append(access)
return results
45 changes: 40 additions & 5 deletions src/psyclone/psyir/nodes/call.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from __future__ import annotations

from collections.abc import Iterable
from typing import List, Tuple, Union, Optional
from typing import Tuple, Union, Optional

from psyclone.configuration import Config
from psyclone.core import AccessType, VariablesAccessMap
Expand All @@ -20,6 +20,7 @@
from psyclone.psyir.nodes.container import Container
from psyclone.psyir.nodes.statement import Statement
from psyclone.psyir.nodes.datanode import DataNode
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.nodes.routine import Routine
from psyclone.psyir.symbols import (
Expand Down Expand Up @@ -502,7 +503,7 @@ def copy(self):

return new_copy

def get_callees(self) -> List[Routine]:
def get_callees(self) -> list[Routine]:
'''
Searches for the implementation(s) of all potential target routines
for this Call. It does *not* attempt to resolve static polymorphism
Expand Down Expand Up @@ -758,7 +759,7 @@ def type_symbols_match(type1: Union[DataTypeSymbol, DataType],
f"'{routine_arg_str}' ({dummy_type})"
)

def get_argument_map(self, routine: Routine) -> List[int]:
def get_argument_map(self, routine: Routine) -> list[int]:
'''Return a list of indices mapping from each argument of this
call to the corresponding entry in the argument list of the
supplied routine.
Expand All @@ -774,7 +775,7 @@ def get_argument_map(self, routine: Routine) -> List[int]:
'''
# Create a copy of the list of actual arguments to the routine.
# Once an argument has been successfully matched, set it to 'None'
routine_argument_list: List[DataSymbol] = (
routine_argument_list: list[DataSymbol] = (
routine.symbol_table.argument_list[:]
)

Expand Down Expand Up @@ -859,7 +860,7 @@ def get_argument_map(self, routine: Routine) -> List[int]:
def get_callee(
self,
use_first_callee_and_no_arg_check: bool = False
) -> Tuple[Routine, List[int]]:
) -> Tuple[Routine, list[int]]:
'''
Searches for the implementation(s) of the target routine for this Call
including argument checks.
Expand Down Expand Up @@ -911,3 +912,37 @@ def get_callee(
f"No matching routine found for '{call_str}':"
"\n" + error_msg
)

def next_accesses(self) -> list[Node]:
'''
:returns: the next_accesses of children of this Call.
'''
# Avoid circular import
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
next_accesses = []
# Find all the children references
refs = [ref for ref in self.walk(Reference) if not
isinstance(ref.symbol, RoutineSymbol)]
chain = DefinitionUseChain(refs)
access_dict = chain.find_forward_accesses()
for access in access_dict:
self._merge_accesses(next_accesses, access_dict[access])
return next_accesses

def previous_accesses(self) -> list[Node]:
'''
:returns: the previous_accesses of children of this Call.
'''
# Avoid circular import
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
prev_accesses = []
# Find all the children references
refs = [ref for ref in self.walk(Reference) if not
isinstance(ref.symbol, RoutineSymbol)]
chain = DefinitionUseChain(refs)
access_dict = chain.find_backward_accesses()
for access in access_dict:
self._merge_accesses(prev_accesses, access_dict[access])
return prev_accesses
16 changes: 16 additions & 0 deletions src/psyclone/psyir/nodes/codeblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,22 @@ def get_fortran_lines(self) -> list[str]:
return []
raise NotImplementedError("Use appropriate CodeBlock subclass")

def next_accesses(self) -> list[Node]:
'''
:returns: the next_accesses for the child References of this
CodeBlock.
'''
# We can use the default implementation from Statement.
return super().next_accesses()

def previous_accesses(self) -> list[Node]:
'''
:returns: the previous_accesses for the child References of this
CodeBlock.
'''
# We can use the default implementation from Statement.
return super().previous_accesses()


class Fparser2CodeBlock(CodeBlock):
''' The fparser2 implementation of CodeBlock. '''
Expand Down
35 changes: 35 additions & 0 deletions src/psyclone/psyir/nodes/directive.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from psyclone.psyir.nodes.array_of_structures_reference import (
ArrayOfStructuresReference)
from psyclone.psyir.nodes.clause import Clause
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.nodes.schedule import Schedule
from psyclone.psyir.nodes.statement import Statement
Expand Down Expand Up @@ -214,6 +215,24 @@ def clauses(self) -> Tuple[Clause]:
return tuple(self.children[1:])
return ()

def next_accesses(self) -> list[Node]:
'''
The next_accesses of a directive is the combined next_accesses
of the Nodes in the dir_body.

:returns: the next_accesses for this directive.
'''
return self._get_next_accesses(self.dir_body.children[:])

def previous_accesses(self) -> list[Node]:
'''
The next_accesses of a directive is the combined previous_accesses
of the Nodes in the dir_body.

:returns: the previous_accesses for this directive.
'''
return self._get_prev_accesses(self.dir_body.children[:])


class StandaloneDirective(Directive):
'''
Expand Down Expand Up @@ -250,6 +269,22 @@ def clauses(self) -> Tuple[Clause]:
'''
return tuple(self.children)

def next_accesses(self) -> list[Node]:
'''
Standalone Directives have no next_accesses.

:returns: an empty list.
'''
return []

def previous_accesses(self) -> list[Node]:
'''
Standalone Directives have no previous_accesses.

:returns: an empty list.
'''
return []


# For automatic API documentation generation
__all__ = ["Directive", "RegionDirective", "StandaloneDirective"]
65 changes: 65 additions & 0 deletions src/psyclone/psyir/nodes/if_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
from psyclone.core import VariablesAccessMap
from psyclone.errors import InternalError, GenerationError
from psyclone.psyir.nodes.datanode import DataNode
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.nodes.schedule import Schedule
from psyclone.psyir.nodes.statement import Statement

Expand Down Expand Up @@ -164,3 +166,66 @@ def reference_accesses(self) -> VariablesAccessMap:
if self.else_body:
var_accesses.update(self.else_body.reference_accesses())
return var_accesses

def next_accesses(self) -> list[Node]:
'''
:returns: the combined next_accesses for the children of this IfBlock.
'''
access_nodes = []
for child in self.if_body:
access_nodes.append(child)
if self.else_body:
for child in self.else_body:
access_nodes.append(child)
next_accesses = self._get_next_accesses(access_nodes)
# Find all the next_accesses for the References in the condition.
# Avoid circular import
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
refs = []
# Use a single call to the DUC's to compute any next_accesses
# from the loop's variable, start, stop and step.
for ref in self.condition.walk(Reference):
refs.append(ref)
chain = DefinitionUseChain(refs)
var_accesses = chain.find_forward_accesses()
results = []
for sig in var_accesses:
for access in var_accesses[sig]:
if all(x is not access for x in results):
results.append(access)
self._merge_accesses(next_accesses, results)

return next_accesses

def previous_accesses(self) -> list[Node]:
'''
:returns: the combined previous_accesses for the children of this
IfBlock.
'''
access_nodes = []
for child in self.if_body:
access_nodes.append(child)
if self.else_body:
for child in self.else_body:
access_nodes.append(child)
prev_accesses = self._get_prev_accesses(access_nodes)
# Find all the previous_accesses for the References in the condition.
# Avoid circular import
# pylint: disable=import-outside-toplevel
from psyclone.psyir.tools import DefinitionUseChain
refs = []
# Use a single call to the DUC's to compute any next_accesses
# from the loop's variable, start, stop and step.
for ref in self.condition.walk(Reference):
refs.append(ref)
chain = DefinitionUseChain(refs)
var_accesses = chain.find_backward_accesses()
results = []
for sig in var_accesses:
for access in var_accesses[sig]:
if all(x is not access for x in results):
results.append(access)
self._merge_accesses(prev_accesses, results)

return prev_accesses
Loading
Loading