Skip to content
Open
Show file tree
Hide file tree
Changes from 4 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
Empty file added examples/nemo/scripts/out
Empty file.
33 changes: 33 additions & 0 deletions examples/nemo/scripts/out.F90
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module stringop
Comment thread
arporter marked this conversation as resolved.
Outdated
implicit none
public

contains
subroutine cmpblank(str)
use profile_psy_data_mod, only : profile_PSyDataType
character(len=*), intent(inout) :: str
integer :: lcc
integer :: ipb
type(profile_PSyDataType), save, target :: profile_psy_data

CALL profile_psy_data % PreStart("stringop", "cmpblank-r0", 0, 0)
lcc = LEN_TRIM(str)
ipb = 1
do while (.true.)
if (ipb >= lcc) then
! PSyclone CodeBlock (unsupported code) reason:
! - Unsupported statement: Exit_Stmt
EXIT
end if
if (str(ipb:ipb + 1) == ' ') then
str(ipb + 1:) = str(ipb + 2:lcc)
lcc = lcc - 1
else
ipb = ipb + 1
end if
end do
CALL profile_psy_data % PostEnd

end subroutine cmpblank

end module stringop
33 changes: 33 additions & 0 deletions examples/nemo/scripts/stringop.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
MODULE stringop
Comment thread
arporter marked this conversation as resolved.
Outdated
!$AGRIF_DO_NOT_TREAT
!-
!$Id: stringop.f90 2281 2010-10-15 14:21:13Z smasson $
!-
! This software is governed by the CeCILL license
! See IOIPSL/IOIPSL_License_CeCILL.txt
!---------------------------------------------------------------------
CONTAINS
!=
SUBROUTINE cmpblank (str)
!---------------------------------------------------------------------
!- Compact blanks
!---------------------------------------------------------------------
CHARACTER(LEN=*),INTENT(inout) :: str
!-
INTEGER :: lcc,ipb
!---------------------------------------------------------------------
lcc = LEN_TRIM(str)
ipb = 1
DO
IF (ipb >= lcc) EXIT
IF (str(ipb:ipb+1) == ' ') THEN
str(ipb+1:) = str(ipb+2:lcc)
lcc = lcc-1
ELSE
ipb = ipb+1
ENDIF
ENDDO
!----------------------
END SUBROUTINE cmpblank
!===
END MODULE stringop
15 changes: 4 additions & 11 deletions examples/nemo/scripts/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@
from psyclone.psyir.symbols import DataSymbol, ArrayType
from psyclone.psyir.transformations import (
ArrayAssignment2LoopsTrans, HoistLoopBoundExprTrans, HoistLocalArraysTrans,
HoistTrans, InlineTrans, Maxval2LoopTrans, Sum2LoopTrans, Minval2LoopTrans,
Product2LoopTrans, ProfileTrans, OMPMinimiseSyncTrans,
HoistTrans, InlineTrans, ProfileTrans, OMPMinimiseSyncTrans,
Reference2ArrayRangeTrans, ScalarisationTrans, IncreaseRankLoopArraysTrans,
MaximalRegionTrans, TransformationError, DataNodeToTempTrans)
MaximalRegionTrans, TransformationError, DataNodeToTempTrans,
Intrinsic2CodeMetaTrans)

# USE statements to chase to gather additional symbol information.
NEMO_MODULES_TO_IMPORT = [
Expand Down Expand Up @@ -186,14 +186,7 @@ def normalise_loops(
if loopify_array_intrinsics:
for intr in schedule.walk(IntrinsicCall):
try:
if intr.intrinsic.name == "MAXVAL":
Maxval2LoopTrans().apply(intr, verbose=True)
elif intr.intrinsic.name == "SUM":
Sum2LoopTrans().apply(intr, verbose=True)
elif intr.intrinsic.name == "MINVAL":
Minval2LoopTrans().apply(intr, verbose=True)
elif intr.intrinsic.name == "PRODUCT":
Product2LoopTrans().apply(intr, verbose=True)
Intrinsic2CodeMetaTrans().apply(intr, verbose=True)
Comment thread
arporter marked this conversation as resolved.
Outdated
except TransformationError as err:
print(err.value)

Expand Down
6 changes: 5 additions & 1 deletion src/psyclone/psyGen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2372,7 +2372,11 @@ def split_kwargs(self, **kwargs) -> tuple[dict[str, Any]]:
if key in trans.get_valid_options():
other_dicts[idx][key] = kwargs[key]
if key not in type(self).get_valid_options():
del first_dict[key]
# Sometimes we may have the same option in multiple
# subtransformations, so we only delete the key
# from the first_dict if its still present.
Comment thread
arporter marked this conversation as resolved.
Outdated
if key in first_dict:
del first_dict[key]

return first_dict, *other_dicts

Expand Down
3 changes: 3 additions & 0 deletions src/psyclone/psyir/transformations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
# Metatransformations
from psyclone.psyir.transformations.metatransformations.omp_cpu_routine_trans\
import OMPCPURoutineTrans
from psyclone.psyir.transformations.metatransformations.\
intrinsic2code_metatrans import Intrinsic2CodeMetaTrans

# For AutoAPI documentation generation
__all__ = [
Expand Down Expand Up @@ -173,4 +175,5 @@
"OMPCriticalTrans",
"MaximalOMPParallelRegionTrans",
"OMPParallelTrans",
"Intrinsic2CodeMetaTrans",
Comment thread
arporter marked this conversation as resolved.
Outdated
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# -----------------------------------------------------------------------------
# SPDX-FileCopyrightText: Copyright (c) 2026 Science and Technology
# Facilities Council
# SPDX-License-Identifier: BSD-3-Clause
# See the full LICENSE file in the project root for details.
# -----------------------------------------------------------------------------

'''This module contains the Intrinsic2CodeTrans metatransformation.'''

from psyclone.psyGen import Transformation
from psyclone.psyir.nodes import IntrinsicCall
from psyclone.psyir.transformations.intrinsics.maxval2loop_trans\
import Maxval2LoopTrans
from psyclone.psyir.transformations.intrinsics.minval2loop_trans\
import Minval2LoopTrans
from psyclone.psyir.transformations.intrinsics.sum2loop_trans\
import Sum2LoopTrans
from psyclone.psyir.transformations.intrinsics.product2loop_trans\
import Product2LoopTrans
from psyclone.utils import transformation_documentation_wrapper


@transformation_documentation_wrapper
class Intrinsic2CodeMetaTrans(Transformation):
Comment thread
arporter marked this conversation as resolved.
Outdated
'''This metatransformation applies any of the Intrinsic2Code
transformations to the provided input. The available transformations are
Maxval2LoopTrans, Sum2LoopTrans, Minval2LoopTrans, or Product2LoopTrans.

'''
_SUB_TRANSFORMATIONS = [Maxval2LoopTrans, Sum2LoopTrans,
Minval2LoopTrans, Product2LoopTrans]

# Create a map of intrinsic names to the appropriate Intrinsic2Code
# transformation.
intrinsic_to_trans = {"MAXVAL": Maxval2LoopTrans,
"SUM": Sum2LoopTrans,
"MINVAL": Minval2LoopTrans,
"PRODUCT": Product2LoopTrans}

def validate(self, node: IntrinsicCall, **kwargs) -> None:
'''
Validates the input options.

:param node: the IntrinsicCall to be transformed.

:raises TypeError: if the input node is not an IntrinsicCall.
'''
# Validate the provided options are allowed and typed correctly.
self.validate_options(**kwargs)

if not isinstance(node, IntrinsicCall):
raise TypeError(
f"Input node to {self.name} must be an IntrinsicCall but "
f"received '{type(node).__name__}'."
)

def apply(self, node: IntrinsicCall, **kwargs) -> None:
'''
Applies the appropriate Intrinsic2Code transformation to the provided
input node.

:param node: the IntrinsicCall to be transformed.
'''
# Split the options for the subtransformations. The options are
# returned in the order of the _SUB_TRANSFORMATIONS list.
kwargs_dict = {}
local_kwargs, kwargs_dict["MAXVAL"], kwargs_dict["SUM"], \
kwargs_dict["MINVAL"], kwargs_dict["PRODUCT"] = \
self.split_kwargs(**kwargs)

self.validate(node, **local_kwargs)

# If the intrinsic is one of the supported intrinsics then
# apply the relevant transformation.
if node.intrinsic.name in Intrinsic2CodeMetaTrans.intrinsic_to_trans:
Comment thread
arporter marked this conversation as resolved.
Outdated
Intrinsic2CodeMetaTrans.intrinsic_to_trans[node.intrinsic.name]().\
apply(node, **kwargs_dict[node.intrinsic.name])
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# -----------------------------------------------------------------------------
# SPDX-FileCopyrightText: Copyright (c) 2026 Science and Technology
# Facilities Council
# SPDX-License-Identifier: BSD-3-Clause
# See the full LICENSE file in the project root for details.
# -----------------------------------------------------------------------------

'''This module contains the tests for the Intrinsic2CodeMetaTrans
metatransformation.'''

import pytest
from psyclone.psyir.nodes import IntrinsicCall
from psyclone.psyir.transformations import Intrinsic2CodeMetaTrans


def test_intrinsic2code_trans_validate(fortran_reader):
'''
Tests the validate method of the Intrinsic2CodeMetaTrans
metatransformation.
'''
with pytest.raises(TypeError) as err:
Intrinsic2CodeMetaTrans().validate(123)
assert ("Input node to Intrinsic2CodeMetaTrans must be an IntrinsicCall "
"but received 'int'." in str(err.value))


@pytest.mark.parametrize("code, expected", [
("j = MAXVAL(i)",
""" reduction_var = -HUGE(reduction_var)
do idx = LBOUND(i, dim=1), UBOUND(i, dim=1), 1
reduction_var = MAX(reduction_var, i(idx))
enddo
j = reduction_var"""),
("j = MINVAL(i)",
""" reduction_var = HUGE(reduction_var)
do idx = LBOUND(i, dim=1), UBOUND(i, dim=1), 1
reduction_var = MIN(reduction_var, i(idx))
enddo
j = reduction_var"""),
("j = PRODUCT(i)",
""" reduction_var = 1
do idx = LBOUND(i, dim=1), UBOUND(i, dim=1), 1
reduction_var = reduction_var * i(idx)
enddo
j = reduction_var"""),
("j = SUM(i)",
"""reduction_var = 0
do idx = LBOUND(i, dim=1), UBOUND(i, dim=1), 1
reduction_var = reduction_var + i(idx)
enddo
j = reduction_var"""),
("j = UBOUND(i)", "j = UBOUND(i)"),
])
def test_intrinsic2code_trans_apply(fortran_reader, fortran_writer,
code, expected):
'''Test the apply function of the Intrinsic2CodeMetaTrans
metatransformation.
'''
code = f"""subroutine test
integer, dimension(:) :: i
integer :: j

{code}

end subroutine test"""
psyir = fortran_reader.psyir_from_source(code)
intrinsic = psyir.walk(IntrinsicCall)[0]
Intrinsic2CodeMetaTrans().apply(intrinsic)

out = fortran_writer(psyir)
print(out)
correct = f"{expected}"
assert correct in out
Loading