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

(Closes #2499) scalarization transformation implementation #2563

Merged
merged 74 commits into from
Feb 27, 2025
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
59d9875
First code towards #2499
LonelyCat124 Apr 29, 2024
ede95c7
forgotten file
LonelyCat124 Apr 29, 2024
6ae3ae3
First implementation of scalarization_trans and unit tests for the pr…
LonelyCat124 Apr 30, 2024
c7cf88c
Linting errors
LonelyCat124 Apr 30, 2024
577d702
Linting errors
LonelyCat124 Apr 30, 2024
d76bfb6
Final commits ready for a review
LonelyCat124 May 1, 2024
2523a6b
Added compile test
LonelyCat124 May 1, 2024
fece2bd
linting
LonelyCat124 May 1, 2024
ed75417
Changes to use filter to make the code easier to understand
LonelyCat124 May 20, 2024
8504137
Merged master
LonelyCat124 Jan 9, 2025
bd2144b
Changes to work with master
LonelyCat124 Jan 9, 2025
047c4a6
First section of rewriting, coverage issues to fix
LonelyCat124 Jan 10, 2025
b1d9544
linting error
LonelyCat124 Jan 10, 2025
2988358
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Jan 10, 2025
dc69373
Updated tests for coverage. Now need to do some more complex function…
LonelyCat124 Jan 10, 2025
1a1531a
Missing coverage for other types of read
LonelyCat124 Jan 10, 2025
a506244
linting fix
LonelyCat124 Jan 10, 2025
75b77d7
Added another test
LonelyCat124 Jan 10, 2025
280cdb6
Added documentation to scalarization trans including an example
LonelyCat124 Jan 13, 2025
c97975f
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Jan 13, 2025
74c7081
Fixed doc errors
LonelyCat124 Jan 14, 2025
058b3ef
Changes for the review
LonelyCat124 Jan 22, 2025
fae6466
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Jan 22, 2025
4984dcd
Fixed the docuemntation
LonelyCat124 Jan 22, 2025
caf0176
Fixed linting
LonelyCat124 Jan 22, 2025
c4b9641
Changes towards review, blocked by #2870
LonelyCat124 Jan 23, 2025
e6c3072
Remove failing test that didn't meet the Fortran standard
LonelyCat124 Jan 23, 2025
ef3cd34
Added the transformation into the User guide
LonelyCat124 Jan 23, 2025
6d8bff5
Scalarize every loop to ensure nothing breaks in NEMO - Revert this l…
LonelyCat124 Jan 25, 2025
4974a6e
Fix tests to compile
LonelyCat124 Jan 27, 2025
409b859
Linting fix
LonelyCat124 Jan 27, 2025
8d51936
Failure to import scalarizationtrans fix
LonelyCat124 Jan 27, 2025
2ce0efa
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Jan 27, 2025
dbae47c
Fix a bug from NEMO4 integration tests where the transformation faile…
LonelyCat124 Jan 27, 2025
a897bf9
git pushMerge branch '2499_scalarization_trans' of github.com:stfc/PS…
LonelyCat124 Jan 27, 2025
a840c8b
Fix another NEMO4 failure case
LonelyCat124 Jan 28, 2025
01912bd
fixed the issue in definition use chains when we find empty scopes
LonelyCat124 Jan 28, 2025
9e75ce6
flake issues
LonelyCat124 Jan 28, 2025
0b37212
Testing scalarization in passthrough instead of on GPU
LonelyCat124 Jan 28, 2025
9818e4b
Go again
LonelyCat124 Jan 29, 2025
c795eb1
another change to test things as we need to skip some files for now w…
LonelyCat124 Jan 29, 2025
4093d66
run the passthrough code for nemo4
LonelyCat124 Jan 29, 2025
956c164
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Jan 31, 2025
250c259
Fix known bugs scalarizing NEMO
LonelyCat124 Jan 31, 2025
51814b5
linting
LonelyCat124 Jan 31, 2025
94f99eb
Linting
LonelyCat124 Jan 31, 2025
88c1eb3
Failing test added to try to work out NEMO5 issues
LonelyCat124 Feb 4, 2025
453a56b
Fix inquiry behaviour for is_read
LonelyCat124 Feb 4, 2025
c17a22d
Linting [skip-ci]
LonelyCat124 Feb 4, 2025
a0e7f2b
Change to handle inquiry functions in definitionusechains
LonelyCat124 Feb 4, 2025
173093d
Linting
LonelyCat124 Feb 4, 2025
1300fcf
Linting
LonelyCat124 Feb 4, 2025
51fe018
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Feb 17, 2025
728dd7b
Changes to add less_than to symbolic maths and to handle scalarizatio…
LonelyCat124 Feb 17, 2025
4d4fbc9
linting
LonelyCat124 Feb 17, 2025
02de511
Swapping non-3.8 compatible type hint
LonelyCat124 Feb 17, 2025
37d9284
Fixing coverage
LonelyCat124 Feb 17, 2025
9e7c9b8
linting
LonelyCat124 Feb 17, 2025
e02b914
Changes to fix coverage!
LonelyCat124 Feb 17, 2025
056f577
Test fix to ensure it tests the expected part of the code
LonelyCat124 Feb 18, 2025
b766dfb
linting
LonelyCat124 Feb 18, 2025
a16eac4
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Feb 19, 2025
ba8c0c1
Merged master
LonelyCat124 Feb 20, 2025
a64b6ab
Merge branch '2499_scalarization_trans' of github.com:stfc/PSyclone i…
LonelyCat124 Feb 20, 2025
756e152
Moving scalarization test into the cpu transformation script
LonelyCat124 Feb 24, 2025
a6d2fae
linting error
LonelyCat124 Feb 24, 2025
bf3eb0b
Fix bug when there is a write inside a conditional statement
LonelyCat124 Feb 25, 2025
75b7ca6
Missed a file
LonelyCat124 Feb 25, 2025
80dba44
Cleaned up the code ready for review
LonelyCat124 Feb 26, 2025
5c0557f
Error in transform script
LonelyCat124 Feb 26, 2025
027d9c0
Merge branch 'master' into 2499_scalarization_trans
LonelyCat124 Feb 26, 2025
12835bf
Changes for review
LonelyCat124 Feb 27, 2025
c28fea6
#2499 Update changelog, increase version, and fix nemo passthrough
sergisiso Feb 27, 2025
612f264
#2499 Rename scalarization to scalarisation
sergisiso Feb 27, 2025
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 src/psyclone/psyir/transformations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@
ReplaceInductionVariablesTrans
from psyclone.psyir.transformations.reference2arrayrange_trans import \
Reference2ArrayRangeTrans
from psyclone.psyir.transformations.scalarization_trans import \
ScalarizationTrans


# For AutoAPI documentation generation
Expand Down Expand Up @@ -143,4 +145,5 @@
'Reference2ArrayRangeTrans',
'RegionTrans',
'ReplaceInductionVariablesTrans',
'ScalarizationTrans',
'TransformationError']
212 changes: 212 additions & 0 deletions src/psyclone/psyir/transformations/scalarization_trans.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2017-2024, Science and Technology Facilities Council.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
# -----------------------------------------------------------------------------
# Author: A. B. G. Chalk, STFC Daresbury Lab

'''This module provides the sclarization transformation class.'''

import itertools

from psyclone.core import VariablesAccessInfo
from psyclone.psyGen import Kern
from psyclone.psyir.nodes import Assignment, Call, CodeBlock, IfBlock, \
Reference, Routine
from psyclone.psyir.symbols import DataSymbol
from psyclone.psyir.transformations.loop_trans import LoopTrans


class ScalarizationTrans(LoopTrans):

def _find_potential_scalarizable_array_symbols(self, node, var_accesses):

potential_arrays = []
signatures = var_accesses.all_signatures
for signature in signatures:
# Skip over non-arrays
if not var_accesses[signature].is_array():
continue
# Skip over non-local symbols
base_symbol = var_accesses[signature].all_accesses[0].node.symbol
if not base_symbol.is_automatic:
continue
array_indices = None
scalarizable = True
for access in var_accesses[signature].all_accesses:
if array_indices is None:
array_indices = access.component_indices
# For some reason using == on the component_lists doesn't work
elif array_indices[:] != access.component_indices[:]:
scalarizable = False
break
# For each index, we need to check they're not written to in
# the loop.
flattened_indices = list(itertools.chain.from_iterable(
array_indices))
for index in flattened_indices:
sig, _ = index.get_signature_and_indices()
if var_accesses[sig].is_written():
scalarizable = False
break
if scalarizable:
potential_arrays.append(signature)

return potential_arrays

def _check_first_access_is_write(self, node, var_accesses, potentials):
potential_arrays = []

for signature in potentials:
if var_accesses[signature].is_written_first():
potential_arrays.append(signature)

return potential_arrays

def _check_valid_following_access(self, node, var_accesses, potentials):
potential_arrays = []

for signature in potentials:
# Find the last access of each signature
last_access = var_accesses[signature].all_accesses[-1].node
# Find the next access to this symbol
next_access = last_access.next_access()
# If we don't use this again then its valid
if next_access is None:
potential_arrays.append(signature)
continue
# If we do and the next_access has an ancestor IfBlock
# that isn't an ancestor of the loop then its not valid since
# we aren't tracking down what the condition-dependent next
# use really is.
if_ancestor = next_access.ancestor(IfBlock)

# If abs_position of if_ancestor is > node.abs_position
# its not an ancestor of us.
if (if_ancestor is not None and
if_ancestor.abs_position > node.abs_position):
# Not a valid next_access pattern.
continue

# If next access is the LHS of an assignment, we need to
# check that it doesn't also appear on the RHS. If so its
# not a valid access
# I'm not sure this code is reachable
# if (isinstance(next_access.parent, Assignment) and
# next_access.parent.lhs is next_access and
# (next_access.next_access() is not None and
# next_access.next_access().ancestor(Assignment) is
# next_access.parent)):
# continue

# If next access is the RHS of an assignment then we need to
# skip it
ancestor_assign = next_access.ancestor(Assignment)
if (ancestor_assign is not None and
ancestor_assign.lhs is not next_access):
continue

# If it has an ancestor that is a CodeBlock or Call or Kern
# then we can't guarantee anything, so we remove it.
if (next_access.ancestor((CodeBlock, Call, Kern))
is not None):
continue

potential_arrays.append(signature)

return potential_arrays

def apply(self, node, options=None):
'''Apply the scalarization transformation to a loop.
All of the array accesses that are identified as being able to be
scalarized will be transformed by this transformation.

An array access will be scalarized if:
1. All accesses to the array use the same indexing statement.
2. All References contained in the indexing statement are not modified
inside of the loop (loop variables are ok).
3. The array symbol is either not accessed again or is written to
as its next access. If the next access is inside a conditional
that is not an ancestor of the input loop, then PSyclone will
assume that we cannot scalarize that value instead of attempting to
understand the control flow.
4. TODO - The array symbol is a local variable.

:param node: the supplied loop to apply scalarization to.
:type node: :py:class:`psyclone.psyir.nodes.Loop`
:param options: a dictionary with options for transformations.
:type options: Optional[Dict[str, Any]]

'''
# For each array reference in the Loop:
# Find every access to the same symbol in the loop
# They all have to be accessed with the same index statement, and
# that index needs to not be written to inside the loop body.
# For each symbol that meets this criteria, we then need to check the
# first access is a write
# Then, for each symbol still meeting this criteria, we need to find
# the next access outside of this loop. If its inside an ifblock that
# is not an ancestor of this loop then we refuse to scalarize for
# simplicity. Otherwise if its a read we can't scalarize safely.
# If its a write then this symbol can be scalarized.

var_accesses = VariablesAccessInfo(nodes=node.loop_body)

# Find all the ararys that are only accessed by a single index, and
# that index is only read inside the loop.
potential_targets = self._find_potential_scalarizable_array_symbols(
node, var_accesses)

# Now we need to check the first access is a write and remove those
# that aren't.
potential_targets = self._check_first_access_is_write(
node, var_accesses, potential_targets)

# Check the values written to these arrays are not used after this loop
finalised_targets = self._check_valid_following_access(
node, var_accesses, potential_targets)

routine_table = node.ancestor(Routine).symbol_table
# For each finalised target we can replace them with a scalarized
# symbol
for target in finalised_targets:
target_accesses = var_accesses[target].all_accesses
first_access = target_accesses[0].node
symbol_type = first_access.symbol.datatype.datatype
symbol_name = first_access.symbol.name
scalar_symbol = routine_table.new_symbol(
root_name=f"{symbol_name}_scalar",
symbol_type=DataSymbol,
datatype=symbol_type)
ref_to_copy = Reference(scalar_symbol)
for access in target_accesses:
node = access.node
node.replace_with(ref_to_copy.copy())
Loading
Loading