From 3047fdd6fd39c716814c9c00ce66939a0dfd03d6 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 16 Dec 2024 18:13:05 +0100 Subject: [PATCH 01/25] [ReplaceRefByLiteral] transformation first draft --- .../psyir/transformations/__init__.py | 84 ++++++----- .../replace_reference_by_literal_trans.py | 135 ++++++++++++++++++ ...replace_reference_by_literal_trans_test.py | 135 ++++++++++++++++++ 3 files changed, 315 insertions(+), 39 deletions(-) create mode 100644 src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py create mode 100644 src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py diff --git a/src/psyclone/psyir/transformations/__init__.py b/src/psyclone/psyir/transformations/__init__.py index 6b5df8ddc9..f7fad89eab 100644 --- a/src/psyclone/psyir/transformations/__init__.py +++ b/src/psyclone/psyir/transformations/__init__.py @@ -103,47 +103,53 @@ from psyclone.psyir.transformations.region_trans import RegionTrans from psyclone.psyir.transformations.replace_induction_variables_trans import \ ReplaceInductionVariablesTrans +from psyclone.psyir.transformations.replace_reference_by_literal_trans import ( + ReplaceReferenceByLiteralTrans, +) from psyclone.psyir.transformations.reference2arrayrange_trans import \ Reference2ArrayRangeTrans # For AutoAPI documentation generation -__all__ = ['ACCKernelsTrans', - 'ACCUpdateTrans', - 'AllArrayAccess2LoopTrans', - 'ArrayAccess2LoopTrans', - 'ArrayAssignment2LoopsTrans', - 'ChunkLoopTrans', - 'ExtractTrans', - 'FoldConditionalReturnExpressionsTrans', - 'HoistLocalArraysTrans', - 'HoistLoopBoundExprTrans', - 'HoistTrans', - 'InlineTrans', - 'Abs2CodeTrans', - 'DotProduct2CodeTrans', - 'Matmul2CodeTrans', - 'Max2CodeTrans', - 'Min2CodeTrans', - 'Sign2CodeTrans', - 'Sum2LoopTrans', - 'LoopFuseTrans', - 'LoopSwapTrans', - 'LoopTiling2DTrans', - 'LoopTrans', - 'Maxval2LoopTrans', - 'Minval2LoopTrans', - 'OMPLoopTrans', - 'OMPTargetTrans', - 'OMPTaskTrans', - 'OMPTaskwaitTrans', - 'ParallelLoopTrans', - 'Product2LoopTrans', - 'ProfileTrans', - 'PSyDataTrans', - 'ReadOnlyVerifyTrans', - 'Reference2ArrayRangeTrans', - 'RegionTrans', - 'ReplaceInductionVariablesTrans', - 'TransformationError', - 'ValueRangeCheckTrans'] +__all__ = [ + "ACCKernelsTrans", + "ACCUpdateTrans", + "AllArrayAccess2LoopTrans", + "ArrayAccess2LoopTrans", + "ArrayAssignment2LoopsTrans", + "ChunkLoopTrans", + "ExtractTrans", + "FoldConditionalReturnExpressionsTrans", + "HoistLocalArraysTrans", + "HoistLoopBoundExprTrans", + "HoistTrans", + "InlineTrans", + "Abs2CodeTrans", + "DotProduct2CodeTrans", + "Matmul2CodeTrans", + "Max2CodeTrans", + "Min2CodeTrans", + "Sign2CodeTrans", + "Sum2LoopTrans", + "LoopFuseTrans", + "LoopSwapTrans", + "LoopTiling2DTrans", + "LoopTrans", + "Maxval2LoopTrans", + "Minval2LoopTrans", + "OMPLoopTrans", + "OMPTargetTrans", + "OMPTaskTrans", + "OMPTaskwaitTrans", + "ParallelLoopTrans", + "Product2LoopTrans", + "ProfileTrans", + "PSyDataTrans", + "ReadOnlyVerifyTrans", + "Reference2ArrayRangeTrans", + "RegionTrans", + "ReplaceInductionVariablesTrans", + "ReplaceReferenceByLiteralTrans", + "TransformationError", + "ValueRangeCheckTrans", +] diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py new file mode 100644 index 0000000000..08767eb68d --- /dev/null +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -0,0 +1,135 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022-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: H. Brunie, University of Grenoble Alpes + +"""Module providing a transformation that replace PsyIR Node static const Reference +with a Literal node when possible. """ + +from psyclone.psyir.symbols import DataSymbol, Symbol, SymbolTable +from psyclone.psyGen import Transformation +from psyclone.psyir.nodes import ( + Routine, + Reference, + Literal, + Container, +) +from psyclone.psyir.transformations.transformation_error import ( + TransformationError, +) + +from typing import Dict + + +class ReplaceReferenceByLiteralTrans(Transformation): + """Replace Reference by Literal. For example: + + TODO: shoule we make it also for the module symbol table parameter? + + eg: + module toto + integer, parameter x= 3 + integer, parameter z = x*2 + + becomes + module toto + integer, parameter x= 3 + integer, parameter z = 3*2 + + """ + + def __str__(self): + return "Replaces all static const Reference by its Literal in a subroutine." + + def _update_param_table( + self, param_table: Dict[str, Literal], symbol_table: SymbolTable + ) -> Dict[str, Literal]: + for sym in symbol_table.symbols: + sym: Symbol + if not isinstance(sym, DataSymbol): + continue + if sym.is_constant: + sym_name = sym.name + if param_table.get(sym_name): + raise TransformationError( + f"Symbol already found {sym_name}." + ) + if not isinstance(sym.initial_value, Literal): + raise TransformationError( + f"DataSymbol {sym_name} initial value is not a Literal {type(sym.initial_value)}." + ) + new_literal = sym.initial_value.copy().detach() + param_table[sym_name] = new_literal + return param_table + + # ------------------------------------------------------------------------ + def apply(self, node: Routine, options=None): + self.validate(node, options) + param_table: Dict[str, Literal] = {} + if isinstance(node.parent, Container): + param_table = self._update_param_table( + param_table, node.parent.symbol_table + ) + + param_table = self._update_param_table(param_table, node.symbol_table) + + for ref in node.walk(Reference): + ref: Reference + if ref.name in param_table: + literal = param_table[ref.name] + ref.replace_with(literal.copy()) + + # ------------------------------------------------------------------------ + def validate(self, node, options=None): + """Perform various checks to ensure that it is valid to apply the + ReplaceReferenceByLiteralTrans transformation to the supplied PSyIR + Node. + + :param node: the node that is being checked. + :type node: :py:class:`psyclone.psyir.nodes.Routine` + + :raises TransformationError: if the node argument is not a \ + Routine. + + """ + if not isinstance(node, Routine): + raise TransformationError( + f"Error in {self.name} transformation. The supplied node " + f"argument should be a PSyIR Routine, but found " + f"'{type(node).__name__}'." + ) + if node.symbol_table is None: + raise TransformationError("SymbolTable is None") + + +__all__ = ["ReplaceReferenceByLiteralTrans"] diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py new file mode 100644 index 0000000000..fa422bc509 --- /dev/null +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -0,0 +1,135 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022-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 derrbled 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: H. Brunie, University of Grenoble Alpes + + +"""This module tests the ReplaceReferenceByLiteralTrans transformation. +""" + +import pytest + +from psyclone.psyir.nodes import Literal, Routine +from psyclone.psyir.symbols import INTEGER_TYPE +from psyclone.psyir.transformations import ( + ReplaceReferenceByLiteralTrans, + TransformationError, +) + + +# ---------------------------------------------------------------------------- +def test_rrbl_general(): + """Test general functionality of the transformation.""" + + rrbl = ReplaceReferenceByLiteralTrans() + + assert ( + str(rrbl) + == "Replaces all static const Reference by its Literal in a subroutine." + ) + assert rrbl.name == "ReplaceReferenceByLiteralTrans" + + +# ---------------------------------------------------------------------------- +def test_rrbl_errors(): + """Test errors that should be thrown.""" + + rrbl = ReplaceReferenceByLiteralTrans() + lit = Literal("1", INTEGER_TYPE) + with pytest.raises(TransformationError) as err: + rrbl.apply(lit) + + assert ( + "Error in ReplaceReferenceByLiteralTrans transformation. The " + "supplied node argument should be a PSyIR Routine, but found " + "'Literal'" in str(err.value) + ) + + +# ---------------------------------------------------------------------------- +def test_rrbl_working(fortran_reader, fortran_writer): + """Tests if subroutine parameters are replaced as expected.""" + source = """program test + use mymod + type(my_type):: t1, t2, t3, t4 + integer, parameter :: x=3, y=12, z=13 + integer, parameter :: u1=1, u2=2, u3=3, u4=4 + + integer i, invariant, ic1, ic2, ic3 + real, dimension(10) :: a + invariant = 1 + do i = 1, 10 + t1%a = z + a(ic1) = u1+(ic1+x)*ic1 + a(ic2) = u2+(ic2+y)*ic2 + a(ic3) = u3+(ic3+z)*ic3 + a(t1%a) = u4+(t1%a+u4*z)*t1%a + end do + end program test""" + psyir = fortran_reader.psyir_from_source(source) + # The first child is the assignment to 'invariant' + routine = psyir.walk(Routine)[0] + + rrbl = ReplaceReferenceByLiteralTrans() + rrbl.apply(routine) + written_code = fortran_writer(routine) + + assert "a(ic1) = 1 + (ic1 + 3) * ic1" in written_code + assert "a(ic2) = 2 + (ic2 + 12) * ic2" in written_code + assert "a(ic3) = 3 + (ic3 + 13) * ic3" in written_code + assert "a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a" in written_code + + +# ---------------------------------------------------------------------------- +# ---------------------------------------------------------------------------- +def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): + source = """module test + integer, parameter :: x=1, y=2, z=3 + real, dimension(10) :: a + contains + subroutine foo() + integer i,ic1 + do i = 1, 10, 5 + ic1 = i+1 + a(ic1) = x+(ic1+y)*ic1 * z + end do + end subroutine + end module""" + psyir = fortran_reader.psyir_from_source(source) + routine = psyir.walk(Routine)[0] + + rrbl = ReplaceReferenceByLiteralTrans() + rrbl.apply(routine) + out = fortran_writer(routine) + + assert "a(ic1) = 1 + (ic1 + 2) * ic1 * 3" in out From 04573fe1aaaff9706972a69764b2e50fbda82bbe Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 10:49:17 +0100 Subject: [PATCH 02/25] [ReplaceRefByLiteral] replace in ArrayType shape. --- .../replace_reference_by_literal_trans.py | 54 +++++++++++++++++-- ...replace_reference_by_literal_trans_test.py | 46 ++++++++++++++++ 2 files changed, 96 insertions(+), 4 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 08767eb68d..c0701b6bdf 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -36,9 +36,16 @@ """Module providing a transformation that replace PsyIR Node static const Reference with a Literal node when possible. """ -from psyclone.psyir.symbols import DataSymbol, Symbol, SymbolTable +from psyclone.psyir.symbols import ( + DataSymbol, + Symbol, + SymbolTable, + ArrayType, + DataType, +) from psyclone.psyGen import Transformation from psyclone.psyir.nodes import ( + DataNode, Routine, Reference, Literal, @@ -48,11 +55,13 @@ TransformationError, ) -from typing import Dict +from typing import Dict, List, Union class ReplaceReferenceByLiteralTrans(Transformation): - """Replace Reference by Literal. For example: + """Replace Reference by Literal if the corresponding symbol from + the symbol table is constant. That is to say this is a Fortran parameter. + For example: TODO: shoule we make it also for the module symbol table parameter? @@ -92,6 +101,32 @@ def _update_param_table( param_table[sym_name] = new_literal return param_table + def _replace_bounds( + self, + current_shape: List[Union[Literal, Reference]], + param_table: Dict[str, Literal], + ) -> List[Union[Literal, Reference]]: + new_shape = [] + for dim in current_shape: + if isinstance(dim, ArrayType.ArrayBounds): + dim_upper = dim.upper.copy() + dim_lower = dim.lower.copy() + ref: DataNode = dim.upper + if isinstance(ref, Reference) and ref.name in param_table: + literal: Literal = param_table[ref.name] + dim_upper = literal.copy() + ref = dim.lower + if isinstance(ref, Reference) and ref.name in param_table: + literal: Literal = param_table[ref.name] + dim_lower = literal.copy() + new_bounds = ArrayType.ArrayBounds(dim_lower, dim_upper) + new_shape.append(new_bounds) + else: + # This dimension is specified with an ArrayType.Extent + # so no need to copy. + new_shape.append(dim) + return new_shape + # ------------------------------------------------------------------------ def apply(self, node: Routine, options=None): self.validate(node, options) @@ -106,9 +141,20 @@ def apply(self, node: Routine, options=None): for ref in node.walk(Reference): ref: Reference if ref.name in param_table: - literal = param_table[ref.name] + literal: Literal = param_table[ref.name] ref.replace_with(literal.copy()) + for sym in node.symbol_table.symbols: + sym: Symbol + if isinstance(sym, DataSymbol) and sym.is_array: + from psyclone.psyir.symbols.datatypes import ( + UnsupportedFortranType, + ) + + if not isinstance(sym.datatype, UnsupportedFortranType): + new_shape = self._replace_bounds(sym.shape, param_table) + sym.datatype = ArrayType(sym.datatype.datatype, new_shape) + # ------------------------------------------------------------------------ def validate(self, node, options=None): """Perform various checks to ensure that it is valid to apply the diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index fa422bc509..989f2d3426 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -133,3 +133,49 @@ def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): out = fortran_writer(routine) assert "a(ic1) = 1 + (ic1 + 2) * ic1 * 3" in out + + +def test_rrbl_array_shape(fortran_reader, fortran_writer): + """Tests if subroutine parameters are replaced as expected.""" + source = """subroutine testtrue() + logical, parameter :: x=.true., y=.false. + integer, parameter :: u=3, size=10 + integer :: i + + real, dimension(size) :: a + if (x) then + do i = 1, size + a(i) = 2+(i+u) + end do + endif + endsubroutine + + subroutine testfalse() + logical, parameter :: x=.true., y=.false. + integer, parameter :: u=3,size=10 + integer :: i + + real, dimension(size) :: a + do i = 1, size + if (y) then + a(i) = 2+(i+u) + endif + end do + end subroutine + """ + psyir = fortran_reader.psyir_from_source(source) + # The first child is the assignment to 'invariant' + mainprog = psyir.walk(Routine)[0] + routine_testfalse = psyir.walk(Routine)[1] + rrbl = ReplaceReferenceByLiteralTrans() + rrbl.apply(mainprog) + written_code = fortran_writer(mainprog) + + assert "a(i) = 2 + (i + 3)" in written_code + assert "if (.true.) then" in written_code + assert "real, dimension(10) :: a" in written_code + assert "do i = 1, 10, 1" in written_code + rrbl.apply(routine_testfalse) + written_code = fortran_writer(routine_testfalse) + assert "a(i) = 2 + (i + 3)" in written_code + assert "if (.false.) then" in written_code From 4ee28242f68f197a378f35d6e8dd780c94e11fd4 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 10:57:30 +0100 Subject: [PATCH 03/25] [gitignore] venv and .vscode --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0fd8c5b122..b77e4731ac 100644 --- a/.gitignore +++ b/.gitignore @@ -27,5 +27,7 @@ src/*.egg-info .idea .rtx.toml .venv +.vscode +venv cov.xml .coverage.* From 8d3c9b4c8e5675af769bf22ca3f1eb922d3dfeeb Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 11:35:54 +0100 Subject: [PATCH 04/25] [ReplaceRefByLiteral] initial value always literal --- .../replace_reference_by_literal_trans.py | 2 + ...replace_reference_by_literal_trans_test.py | 76 +++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index c0701b6bdf..ea7219984f 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -154,6 +154,8 @@ def apply(self, node: Routine, options=None): if not isinstance(sym.datatype, UnsupportedFortranType): new_shape = self._replace_bounds(sym.shape, param_table) sym.datatype = ArrayType(sym.datatype.datatype, new_shape) + ## For debug and triggering raise Error. + self._param_table = param_table # ------------------------------------------------------------------------ def validate(self, node, options=None): diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 989f2d3426..644b46acc2 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -179,3 +179,79 @@ def test_rrbl_array_shape(fortran_reader, fortran_writer): written_code = fortran_writer(routine_testfalse) assert "a(i) = 2 + (i + 3)" in written_code assert "if (.false.) then" in written_code + + +def test_array_type_extend(fortran_reader, fortran_writer): + source = """subroutine foo() + integer, parameter :: a = 3 + integer, dimension(:,a:) :: x + end subroutine""" + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + rbbl = ReplaceReferenceByLiteralTrans() + rbbl.apply(foo) + written_code = fortran_writer(foo) + + assert "integer, dimension(:,3:)" in written_code + + +def test_raise_transformation_error_symbol_table_is_none( + fortran_reader, fortran_writer +): + source = """subroutine foo() + integer, parameter :: a = 3 + integer :: x + x = a + end subroutine""" + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + foo._symbol_table = None + rbbl = ReplaceReferenceByLiteralTrans() + error_str = "" + try: + rbbl.apply(foo) + except TransformationError as e: + error_str = e.__str__() + assert "SymbolTable is None" in error_str + + +def test_raise_transformation_error(fortran_reader, fortran_writer): + source = """subroutine foo() + integer, parameter :: a = 3 + integer :: x + x = a + end subroutine""" + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + rbbl = ReplaceReferenceByLiteralTrans() + rbbl.apply(foo) + error_str = "" + try: + rbbl._update_param_table(rbbl._param_table, foo.symbol_table) + except TransformationError as e: + error_str = e.__str__() + assert "Symbol already found" in error_str + + +def test_raise_transformation_error_initial_value( + fortran_reader, fortran_writer +): + source = """subroutine foo() + character(len=4), parameter :: a = "toto" + character(len=4):: x + x = a + end subroutine""" + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + assert foo.symbol_table is not None + from psyclone.psyir.symbols import DataSymbol + + sym_a: DataSymbol = foo.symbol_table.find_or_create("a") + assert not sym_a.is_constant + rbbl = ReplaceReferenceByLiteralTrans() + error_str = "" + try: + rbbl.apply(foo) + except TransformationError as e: + error_str = e.__str__() + assert not "initial value is not a Literal" in error_str From fdb373865757168834462eca3f0ba1fbb360d68f Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 11:44:54 +0100 Subject: [PATCH 05/25] [ReplaceRefByLiteral] 80 chars exceeded --- .../replace_reference_by_literal_trans.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index ea7219984f..df4c95e656 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -33,8 +33,8 @@ # ----------------------------------------------------------------------------- # Author: H. Brunie, University of Grenoble Alpes -"""Module providing a transformation that replace PsyIR Node static const Reference -with a Literal node when possible. """ +"""Module providing a transformation that replace PsyIR Node static const +Reference with a Literal node when possible. """ from psyclone.psyir.symbols import ( DataSymbol, @@ -78,7 +78,10 @@ class ReplaceReferenceByLiteralTrans(Transformation): """ def __str__(self): - return "Replaces all static const Reference by its Literal in a subroutine." + return ( + "Replaces all static const Reference" + + " by its Literal in a subroutine." + ) def _update_param_table( self, param_table: Dict[str, Literal], symbol_table: SymbolTable @@ -95,7 +98,8 @@ def _update_param_table( ) if not isinstance(sym.initial_value, Literal): raise TransformationError( - f"DataSymbol {sym_name} initial value is not a Literal {type(sym.initial_value)}." + f"DataSymbol {sym_name} initial value is not " + + f"a Literal {type(sym.initial_value)}." ) new_literal = sym.initial_value.copy().detach() param_table[sym_name] = new_literal @@ -152,7 +156,9 @@ def apply(self, node: Routine, options=None): ) if not isinstance(sym.datatype, UnsupportedFortranType): - new_shape = self._replace_bounds(sym.shape, param_table) + new_shape: List[Union[Literal, Reference]] = ( + self._replace_bounds(sym.shape, param_table) + ) sym.datatype = ArrayType(sym.datatype.datatype, new_shape) ## For debug and triggering raise Error. self._param_table = param_table From b19b6a7e2843a1ad97a5956d45091527fa9e453f Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 11:52:58 +0100 Subject: [PATCH 06/25] [ReplaceRefByLiteral] add test showing limit of trans * Thanks Andrew, indeed, BinaryOp can be an valid initial_value --- ...replace_reference_by_literal_trans_test.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 644b46acc2..a9633bbc7f 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -233,11 +233,36 @@ def test_raise_transformation_error(fortran_reader, fortran_writer): assert "Symbol already found" in error_str +def test_raise_transformation_error_initial_value_not_literal( + fortran_reader, fortran_writer +): + """TODO: use sympy maybe to simplify expression before applying + transformation""" + source = """subroutine foo() + integer, parameter :: b = 3+2 + integer :: x + x = b + end subroutine""" + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + assert foo.symbol_table is not None + from psyclone.psyir.symbols import DataSymbol + + rbbl = ReplaceReferenceByLiteralTrans() + error_str = "" + try: + rbbl.apply(foo) + except TransformationError as e: + error_str = e.__str__() + assert "initial value is not a Literal" in error_str + + def test_raise_transformation_error_initial_value( fortran_reader, fortran_writer ): source = """subroutine foo() character(len=4), parameter :: a = "toto" + integer, parameter :: b = 3+2 character(len=4):: x x = a end subroutine""" From bfe75cc7393e1333ef7b52d457c3c2385ea84033 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 11:58:21 +0100 Subject: [PATCH 07/25] [ReplaceRefByLit] flake8 --- .../transformations/replace_reference_by_literal_trans.py | 4 +--- .../replace_reference_by_literal_trans_test.py | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index df4c95e656..8933ad2f9a 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -33,7 +33,7 @@ # ----------------------------------------------------------------------------- # Author: H. Brunie, University of Grenoble Alpes -"""Module providing a transformation that replace PsyIR Node static const +"""Module providing a transformation that replace PsyIR Node static const Reference with a Literal node when possible. """ from psyclone.psyir.symbols import ( @@ -41,7 +41,6 @@ Symbol, SymbolTable, ArrayType, - DataType, ) from psyclone.psyGen import Transformation from psyclone.psyir.nodes import ( @@ -57,7 +56,6 @@ from typing import Dict, List, Union - class ReplaceReferenceByLiteralTrans(Transformation): """Replace Reference by Literal if the corresponding symbol from the symbol table is constant. That is to say this is a Fortran parameter. diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index a9633bbc7f..5c1d6e6b74 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -55,7 +55,8 @@ def test_rrbl_general(): assert ( str(rrbl) - == "Replaces all static const Reference by its Literal in a subroutine." + == "Replaces all static const Reference " + + "by its Literal in a subroutine." ) assert rrbl.name == "ReplaceReferenceByLiteralTrans" @@ -116,7 +117,7 @@ def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): source = """module test integer, parameter :: x=1, y=2, z=3 real, dimension(10) :: a - contains + contains subroutine foo() integer i,ic1 do i = 1, 10, 5 @@ -246,7 +247,6 @@ def test_raise_transformation_error_initial_value_not_literal( psyir = fortran_reader.psyir_from_source(source) foo: Routine = psyir.walk(Routine)[0] assert foo.symbol_table is not None - from psyclone.psyir.symbols import DataSymbol rbbl = ReplaceReferenceByLiteralTrans() error_str = "" @@ -279,4 +279,4 @@ def test_raise_transformation_error_initial_value( rbbl.apply(foo) except TransformationError as e: error_str = e.__str__() - assert not "initial value is not a Literal" in error_str + assert "initial value is not a Literal" not in error_str From 5b06c5b4c35d223d165bc00633a93402856650d5 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Tue, 17 Dec 2024 12:38:35 +0100 Subject: [PATCH 08/25] [RefbyLiteral] flake8 + test sucess --- .../psyir/transformations/replace_reference_by_literal_trans.py | 1 + .../transformations/replace_reference_by_literal_trans_test.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 8933ad2f9a..1d52312bd3 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -56,6 +56,7 @@ from typing import Dict, List, Union + class ReplaceReferenceByLiteralTrans(Transformation): """Replace Reference by Literal if the corresponding symbol from the symbol table is constant. That is to say this is a Fortran parameter. diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 5c1d6e6b74..62b593a41d 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -279,4 +279,4 @@ def test_raise_transformation_error_initial_value( rbbl.apply(foo) except TransformationError as e: error_str = e.__str__() - assert "initial value is not a Literal" not in error_str + assert "initial value is not a Literal" in error_str From ff98ba7ce288e4e4da491e073335821a9d4c0ae0 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Wed, 15 Jan 2025 14:39:34 +0100 Subject: [PATCH 09/25] #2828 fix license date. --- .../psyir/transformations/replace_reference_by_literal_trans.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 1d52312bd3..0d2f48252d 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022-2024, Science and Technology Facilities Council. +# Copyright (c) 2024-2025, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without From c31f4b9d3a757f5744c072c02e591fa6970b0b97 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 11:09:47 +0100 Subject: [PATCH 10/25] #2828 fix module description. --- .../transformations/replace_reference_by_literal_trans.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 0d2f48252d..f2e8c749a0 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -33,8 +33,8 @@ # ----------------------------------------------------------------------------- # Author: H. Brunie, University of Grenoble Alpes -"""Module providing a transformation that replace PsyIR Node static const -Reference with a Literal node when possible. """ +"""Module providing a transformation that replace PsyIR Node representing a +static, constant value with a Literal Node when possible. """ from psyclone.psyir.symbols import ( DataSymbol, @@ -62,6 +62,9 @@ class ReplaceReferenceByLiteralTrans(Transformation): the symbol table is constant. That is to say this is a Fortran parameter. For example: + we should always consider all constant symbols that are in scope, + rather than explicitly looking at the Routine and Container symbol tables? + TODO: shoule we make it also for the module symbol table parameter? eg: @@ -95,6 +98,7 @@ def _update_param_table( raise TransformationError( f"Symbol already found {sym_name}." ) + ## FIXME: Andrew: better if it is skipped quietly if not isinstance(sym.initial_value, Literal): raise TransformationError( f"DataSymbol {sym_name} initial value is not " From 257aac7fd7f10535f1d7ca08c5e07378657051db Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 11:32:49 +0100 Subject: [PATCH 11/25] #2828 class docstring and import sorted. --- .../replace_reference_by_literal_trans.py | 108 ++++++++++++------ ...replace_reference_by_literal_trans_test.py | 3 - 2 files changed, 76 insertions(+), 35 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index f2e8c749a0..705fb5d1b4 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -36,48 +36,92 @@ """Module providing a transformation that replace PsyIR Node representing a static, constant value with a Literal Node when possible. """ -from psyclone.psyir.symbols import ( - DataSymbol, - Symbol, - SymbolTable, - ArrayType, -) +from typing import Dict, List, Union + from psyclone.psyGen import Transformation from psyclone.psyir.nodes import ( + Container, DataNode, - Routine, - Reference, Literal, - Container, + Reference, + Routine, +) +from psyclone.psyir.symbols import ( + ArrayType, + DataSymbol, + Symbol, + SymbolTable, ) from psyclone.psyir.transformations.transformation_error import ( TransformationError, ) -from typing import Dict, List, Union - - class ReplaceReferenceByLiteralTrans(Transformation): - """Replace Reference by Literal if the corresponding symbol from - the symbol table is constant. That is to say this is a Fortran parameter. - For example: - - we should always consider all constant symbols that are in scope, - rather than explicitly looking at the Routine and Container symbol tables? - - TODO: shoule we make it also for the module symbol table parameter? - - eg: - module toto - integer, parameter x= 3 - integer, parameter z = x*2 - - becomes - module toto - integer, parameter x= 3 - integer, parameter z = 3*2 - - """ + ''' + This transformation takes a psyir Routine and replace all Reference psyir + Nodes by Literal if the corresponding symbol from the symbol table is + constant. That is to say the symbol is a Fortran parameter. + For example: + + >>> from psyclone.psyir.backend.fortran import FortranWriter + >>> from psyclone.psyir.symbols import INTEGER_TYPE + >>> from psyclone.psyir.transformations import ReplaceReferenceByLiteralTrans + >>> source = """program test + ... use mymod + ... type(my_type):: t1, t2, t3, t4 + ... integer, parameter :: x=3, y=12, z=13 + ... integer, parameter :: u1=1, u2=2, u3=3, u4=4 + ... integer i, invariant, ic1, ic2, ic3 + ... real, dimension(10) :: a + ... invariant = 1 + ... do i = 1, 10 + ... t1%a = z + ... a(ic1) = u1+(ic1+x)*ic1 + ... a(ic2) = u2+(ic2+y)*ic2 + ... a(ic3) = u3+(ic3+z)*ic3 + ... a(t1%a) = u4+(t1%a+u4*z)*t1%a + ... end do + ... end program test""" + >>> fortran_writer = FortranWriter() + >>> fortran_reader = FortranReader() + >>> psyir = fortran_reader.psyir_from_source(source) + >>> routine = psyir.walk(Routine)[0] + >>> rrbl = ReplaceReferenceByLiteralTrans() + >>> rrbl.apply(routine) + >>> written_code = fortran_writer(routine) + >>> print(written_code) + program test + use mymod + integer, parameter :: x = 3 + integer, parameter :: y = 12 + integer, parameter :: z = 13 + integer, parameter :: u1 = 1 + integer, parameter :: u2 = 2 + integer, parameter :: u3 = 3 + integer, parameter :: u4 = 4 + type(my_type) :: t1 + type(my_type) :: t2 + type(my_type) :: t3 + type(my_type) :: t4 + integer :: i + integer :: invariant + integer :: ic1 + integer :: ic2 + integer :: ic3 + real, dimension(10) :: a + + invariant = 1 + do i = 1, 10, 1 + t1%a = 13 + a(ic1) = 1 + (ic1 + 3) * ic1 + a(ic2) = 2 + (ic2 + 12) * ic2 + a(ic3) = 3 + (ic3 + 13) * ic3 + a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a + enddo + + end program test + + ''' def __str__(self): return ( diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 62b593a41d..f97c1fe86f 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -85,7 +85,6 @@ def test_rrbl_working(fortran_reader, fortran_writer): type(my_type):: t1, t2, t3, t4 integer, parameter :: x=3, y=12, z=13 integer, parameter :: u1=1, u2=2, u3=3, u4=4 - integer i, invariant, ic1, ic2, ic3 real, dimension(10) :: a invariant = 1 @@ -100,11 +99,9 @@ def test_rrbl_working(fortran_reader, fortran_writer): psyir = fortran_reader.psyir_from_source(source) # The first child is the assignment to 'invariant' routine = psyir.walk(Routine)[0] - rrbl = ReplaceReferenceByLiteralTrans() rrbl.apply(routine) written_code = fortran_writer(routine) - assert "a(ic1) = 1 + (ic1 + 3) * ic1" in written_code assert "a(ic2) = 2 + (ic2 + 12) * ic2" in written_code assert "a(ic3) = 3 + (ic3 + 13) * ic3" in written_code From 9e41bcc5d6ba1b24ccec9dcf678354b8a3cb65a3 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 11:37:05 +0100 Subject: [PATCH 12/25] #2828 fix indent --- .../replace_reference_by_literal_trans.py | 65 ++++++++++--------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 705fb5d1b4..cba49afe3b 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -58,38 +58,39 @@ class ReplaceReferenceByLiteralTrans(Transformation): ''' - This transformation takes a psyir Routine and replace all Reference psyir - Nodes by Literal if the corresponding symbol from the symbol table is - constant. That is to say the symbol is a Fortran parameter. - For example: - - >>> from psyclone.psyir.backend.fortran import FortranWriter - >>> from psyclone.psyir.symbols import INTEGER_TYPE - >>> from psyclone.psyir.transformations import ReplaceReferenceByLiteralTrans - >>> source = """program test - ... use mymod - ... type(my_type):: t1, t2, t3, t4 - ... integer, parameter :: x=3, y=12, z=13 - ... integer, parameter :: u1=1, u2=2, u3=3, u4=4 - ... integer i, invariant, ic1, ic2, ic3 - ... real, dimension(10) :: a - ... invariant = 1 - ... do i = 1, 10 - ... t1%a = z - ... a(ic1) = u1+(ic1+x)*ic1 - ... a(ic2) = u2+(ic2+y)*ic2 - ... a(ic3) = u3+(ic3+z)*ic3 - ... a(t1%a) = u4+(t1%a+u4*z)*t1%a - ... end do - ... end program test""" - >>> fortran_writer = FortranWriter() - >>> fortran_reader = FortranReader() - >>> psyir = fortran_reader.psyir_from_source(source) - >>> routine = psyir.walk(Routine)[0] - >>> rrbl = ReplaceReferenceByLiteralTrans() - >>> rrbl.apply(routine) - >>> written_code = fortran_writer(routine) - >>> print(written_code) + This transformation takes a psyir Routine and replace all Reference psyir + Nodes by Literal if the corresponding symbol from the symbol table is + constant. That is to say the symbol is a Fortran parameter. + For example: + + + >>> from psyclone.psyir.backend.fortran import FortranWriter + >>> from psyclone.psyir.symbols import INTEGER_TYPE + >>> from psyclone.psyir.transformations import ReplaceReferenceByLiteralTrans + >>> source = """program test + ... use mymod + ... type(my_type):: t1, t2, t3, t4 + ... integer, parameter :: x=3, y=12, z=13 + ... integer, parameter :: u1=1, u2=2, u3=3, u4=4 + ... integer i, invariant, ic1, ic2, ic3 + ... real, dimension(10) :: a + ... invariant = 1 + ... do i = 1, 10 + ... t1%a = z + ... a(ic1) = u1+(ic1+x)*ic1 + ... a(ic2) = u2+(ic2+y)*ic2 + ... a(ic3) = u3+(ic3+z)*ic3 + ... a(t1%a) = u4+(t1%a+u4*z)*t1%a + ... end do + ... end program test""" + >>> fortran_writer = FortranWriter() + >>> fortran_reader = FortranReader() + >>> psyir = fortran_reader.psyir_from_source(source) + >>> routine = psyir.walk(Routine)[0] + >>> rrbl = ReplaceReferenceByLiteralTrans() + >>> rrbl.apply(routine) + >>> written_code = fortran_writer(routine) + >>> print(written_code) program test use mymod integer, parameter :: x = 3 From 94be55caf1eba1f630354dae15487c61819d9399 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 11:38:37 +0100 Subject: [PATCH 13/25] #2828 remove __str__ method --- .../transformations/replace_reference_by_literal_trans.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index cba49afe3b..3fc5331498 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -124,12 +124,6 @@ class ReplaceReferenceByLiteralTrans(Transformation): ''' - def __str__(self): - return ( - "Replaces all static const Reference" - + " by its Literal in a subroutine." - ) - def _update_param_table( self, param_table: Dict[str, Literal], symbol_table: SymbolTable ) -> Dict[str, Literal]: From cf253a73e891a6cd513b9155259368f77e3659fe Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 12:43:34 +0100 Subject: [PATCH 14/25] #2828 use new comment feature (thx JR) --- .../replace_reference_by_literal_trans.py | 38 +++++++------ ...replace_reference_by_literal_trans_test.py | 54 +++++++++---------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 3fc5331498..790d1cbd41 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -124,8 +124,14 @@ class ReplaceReferenceByLiteralTrans(Transformation): ''' + def __init__(self) -> None: + super().__init__() + self._param_table: Dict[str, Literal] = {} + def _update_param_table( - self, param_table: Dict[str, Literal], symbol_table: SymbolTable + self, + param_table: Dict[str, Literal], + symbol_table: SymbolTable, ) -> Dict[str, Literal]: for sym in symbol_table.symbols: sym: Symbol @@ -134,16 +140,15 @@ def _update_param_table( if sym.is_constant: sym_name = sym.name if param_table.get(sym_name): - raise TransformationError( - f"Symbol already found {sym_name}." - ) - ## FIXME: Andrew: better if it is skipped quietly + message = f"Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found {sym_name}." + sym.preceding_comment += message if not isinstance(sym.initial_value, Literal): - raise TransformationError( - f"DataSymbol {sym_name} initial value is not " + message = ( + f"Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol {sym_name} initial value is not " + f"a Literal {type(sym.initial_value)}." ) - new_literal = sym.initial_value.copy().detach() + sym.preceding_comment += message + new_literal: Literal = sym.initial_value.copy().detach() param_table[sym_name] = new_literal return param_table @@ -176,18 +181,19 @@ def _replace_bounds( # ------------------------------------------------------------------------ def apply(self, node: Routine, options=None): self.validate(node, options) - param_table: Dict[str, Literal] = {} if isinstance(node.parent, Container): - param_table = self._update_param_table( - param_table, node.parent.symbol_table + self._param_table = self._update_param_table( + self._param_table, node.parent.symbol_table ) - param_table = self._update_param_table(param_table, node.symbol_table) + self._param_table = self._update_param_table( + self._param_table, node.symbol_table + ) for ref in node.walk(Reference): ref: Reference - if ref.name in param_table: - literal: Literal = param_table[ref.name] + if ref.name in self._param_table: + literal: Literal = self._param_table[ref.name] ref.replace_with(literal.copy()) for sym in node.symbol_table.symbols: @@ -199,11 +205,9 @@ def apply(self, node: Routine, options=None): if not isinstance(sym.datatype, UnsupportedFortranType): new_shape: List[Union[Literal, Reference]] = ( - self._replace_bounds(sym.shape, param_table) + self._replace_bounds(sym.shape, self._param_table) ) sym.datatype = ArrayType(sym.datatype.datatype, new_shape) - ## For debug and triggering raise Error. - self._param_table = param_table # ------------------------------------------------------------------------ def validate(self, node, options=None): diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index f97c1fe86f..e6df2fd895 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -39,7 +39,7 @@ import pytest -from psyclone.psyir.nodes import Literal, Routine +from psyclone.psyir.nodes import Literal, Routine, Container from psyclone.psyir.symbols import INTEGER_TYPE from psyclone.psyir.transformations import ( ReplaceReferenceByLiteralTrans, @@ -54,9 +54,8 @@ def test_rrbl_general(): rrbl = ReplaceReferenceByLiteralTrans() assert ( - str(rrbl) - == "Replaces all static const Reference " - + "by its Literal in a subroutine." + "psyclone.psyir.transformations.replace_reference_by_literal_trans.ReplaceReferenceByLiteralTrans" + in str(rrbl) ) assert rrbl.name == "ReplaceReferenceByLiteralTrans" @@ -179,7 +178,7 @@ def test_rrbl_array_shape(fortran_reader, fortran_writer): assert "if (.false.) then" in written_code -def test_array_type_extend(fortran_reader, fortran_writer): +def test_rrbl_array_type_extend(fortran_reader, fortran_writer): source = """subroutine foo() integer, parameter :: a = 3 integer, dimension(:,a:) :: x @@ -193,7 +192,7 @@ def test_array_type_extend(fortran_reader, fortran_writer): assert "integer, dimension(:,3:)" in written_code -def test_raise_transformation_error_symbol_table_is_none( +def test_rrbl_raise_transformation_error_symbol_table_is_none( fortran_reader, fortran_writer ): source = """subroutine foo() @@ -213,7 +212,8 @@ def test_raise_transformation_error_symbol_table_is_none( assert "SymbolTable is None" in error_str -def test_raise_transformation_error(fortran_reader, fortran_writer): +def test_rrbl_raise_transformation_error(fortran_reader, fortran_writer): + """""" source = """subroutine foo() integer, parameter :: a = 3 integer :: x @@ -223,15 +223,15 @@ def test_raise_transformation_error(fortran_reader, fortran_writer): foo: Routine = psyir.walk(Routine)[0] rbbl = ReplaceReferenceByLiteralTrans() rbbl.apply(foo) - error_str = "" - try: - rbbl._update_param_table(rbbl._param_table, foo.symbol_table) - except TransformationError as e: - error_str = e.__str__() - assert "Symbol already found" in error_str + rbbl._update_param_table(rbbl._param_table, foo.symbol_table) + written_code = fortran_writer(foo.ancestor(Container)) + assert ( + "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found" + in written_code + ) -def test_raise_transformation_error_initial_value_not_literal( +def test_rrbl_raise_transformation_error_initial_value_not_literal( fortran_reader, fortran_writer ): """TODO: use sympy maybe to simplify expression before applying @@ -246,15 +246,15 @@ def test_raise_transformation_error_initial_value_not_literal( assert foo.symbol_table is not None rbbl = ReplaceReferenceByLiteralTrans() - error_str = "" - try: - rbbl.apply(foo) - except TransformationError as e: - error_str = e.__str__() - assert "initial value is not a Literal" in error_str + rbbl.apply(foo) + written_code = fortran_writer(foo.ancestor(Container)) + assert ( + "Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol b initial value is not a Literal" + in written_code + ) -def test_raise_transformation_error_initial_value( +def test_rrbl_raise_transformation_error_initial_value( fortran_reader, fortran_writer ): source = """subroutine foo() @@ -271,9 +271,9 @@ def test_raise_transformation_error_initial_value( sym_a: DataSymbol = foo.symbol_table.find_or_create("a") assert not sym_a.is_constant rbbl = ReplaceReferenceByLiteralTrans() - error_str = "" - try: - rbbl.apply(foo) - except TransformationError as e: - error_str = e.__str__() - assert "initial value is not a Literal" in error_str + rbbl.apply(foo) + written_code = fortran_writer(foo.ancestor(Container)) + assert ( + "! Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol b initial value is not a Literal" + in written_code + ) From 7bee9367ded885a68fb1a9990b133d56ca8a4203 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 15:03:40 +0100 Subject: [PATCH 15/25] #2828 comment each test --- ...replace_reference_by_literal_trans_test.py | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index e6df2fd895..93882764a1 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -1,7 +1,7 @@ # ----------------------------------------------------------------------------- # BSD 3-Clause License # -# Copyright (c) 2022-2024, Science and Technology Facilities Council. +# Copyright (c) 2024-2025, Science and Technology Facilities Council. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -39,7 +39,7 @@ import pytest -from psyclone.psyir.nodes import Literal, Routine, Container +from psyclone.psyir.nodes import Container, Literal, Routine from psyclone.psyir.symbols import INTEGER_TYPE from psyclone.psyir.transformations import ( ReplaceReferenceByLiteralTrans, @@ -77,8 +77,9 @@ def test_rrbl_errors(): # ---------------------------------------------------------------------------- -def test_rrbl_working(fortran_reader, fortran_writer): +def test_rrbl_in_loop(fortran_reader, fortran_writer): """Tests if subroutine parameters are replaced as expected.""" + source = """program test use mymod type(my_type):: t1, t2, t3, t4 @@ -107,9 +108,11 @@ def test_rrbl_working(fortran_reader, fortran_writer): assert "a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a" in written_code -# ---------------------------------------------------------------------------- -# ---------------------------------------------------------------------------- def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): + """test replacement of reference by a literal defined as constant value in + the module scope + """ + source = """module test integer, parameter :: x=1, y=2, z=3 real, dimension(10) :: a @@ -134,6 +137,7 @@ def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): def test_rrbl_array_shape(fortran_reader, fortran_writer): """Tests if subroutine parameters are replaced as expected.""" + source = """subroutine testtrue() logical, parameter :: x=.true., y=.false. integer, parameter :: u=3, size=10 @@ -179,6 +183,8 @@ def test_rrbl_array_shape(fortran_reader, fortran_writer): def test_rrbl_array_type_extend(fortran_reader, fortran_writer): + """test replacement of lower bound of an array dimension""" + source = """subroutine foo() integer, parameter :: a = 3 integer, dimension(:,a:) :: x @@ -195,6 +201,8 @@ def test_rrbl_array_type_extend(fortran_reader, fortran_writer): def test_rrbl_raise_transformation_error_symbol_table_is_none( fortran_reader, fortran_writer ): + """test raise TransformationError because of None value in SymbolTable""" + source = """subroutine foo() integer, parameter :: a = 3 integer :: x @@ -212,8 +220,11 @@ def test_rrbl_raise_transformation_error_symbol_table_is_none( assert "SymbolTable is None" in error_str -def test_rrbl_raise_transformation_error(fortran_reader, fortran_writer): - """""" +def test_rrbl_write_fortran_comment_warning_about_symbol_found( + fortran_reader, fortran_writer +): + """test fortran code annotation with transformation warning""" + source = """subroutine foo() integer, parameter :: a = 3 integer :: x @@ -234,8 +245,8 @@ def test_rrbl_raise_transformation_error(fortran_reader, fortran_writer): def test_rrbl_raise_transformation_error_initial_value_not_literal( fortran_reader, fortran_writer ): - """TODO: use sympy maybe to simplify expression before applying - transformation""" + """test fortran code annotation with transformation warning""" + source = """subroutine foo() integer, parameter :: b = 3+2 integer :: x @@ -257,6 +268,8 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( def test_rrbl_raise_transformation_error_initial_value( fortran_reader, fortran_writer ): + """test fortran code annotation with transformation warning""" + source = """subroutine foo() character(len=4), parameter :: a = "toto" integer, parameter :: b = 3+2 From 463e64de2aaf4eea0495199480814acc6a24584f Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:03:30 +0100 Subject: [PATCH 16/25] #2828 explicit warning message. --- .../replace_reference_by_literal_trans.py | 35 +++++++++-- ...replace_reference_by_literal_trans_test.py | 62 +++++++++++++++++++ 2 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 790d1cbd41..fb5f2fd34d 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -133,18 +133,41 @@ def _update_param_table( param_table: Dict[str, Literal], symbol_table: SymbolTable, ) -> Dict[str, Literal]: - for sym in symbol_table.symbols: - sym: Symbol - if not isinstance(sym, DataSymbol): - continue + """This methods takes a param_table as entry, updates this dictionary + and then returns the same dictionary updated. + + * Goes through all datasymbols in the symbol_table. + * if symbol already in param_table or initial_value is not Literal: + * annotate code with warning. + * copy and detach the symbol.initial_value (Literal) + * update the param_table with this copy. + * Returns the updated param_table + + :param param_table: To be updated + :type param_table: Dict[str, Literal] + :param symbol_table: scope symbol table to look for the symbols. + :type symbol_table: SymbolTable + :return: the updated param_table (same reference as the entry one) + :rtype: Dict[str, Literal] + """ + for sym in symbol_table.datasymbols: + sym: DataSymbol if sym.is_constant: sym_name = sym.name if param_table.get(sym_name): - message = f"Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found {sym_name}." + message = ( + "Psyclone(ReplaceReferenceByLiteralTrans):" + + f" Symbol already found {sym_name}." + + " A conflict is possible." + + "To avoid replacing by wrong value, " + + "symbol is removed from param_table." + ) sym.preceding_comment += message + param_table.pop(sym_name) if not isinstance(sym.initial_value, Literal): message = ( - f"Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol {sym_name} initial value is not " + "Psyclone(ReplaceReferenceByLiteralTrans): " + + f"DataSymbol {sym_name} initial value is not " + f"a Literal {type(sym.initial_value)}." ) sym.preceding_comment += message diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 93882764a1..7ce41a6f74 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -220,6 +220,68 @@ def test_rrbl_raise_transformation_error_symbol_table_is_none( assert "SymbolTable is None" in error_str +def test_rrbl_conflict_between_module_and_routine_scopes( + fortran_reader, fortran_writer +): + """test fortran code annotation with transformation warning""" + + source = """module toto + integer, parameter :: a=3 +contains + subroutine tata() + call foo() + end subroutine + subroutine foo() + integer, parameter :: x=a + integer, parameter :: a=2 + integer, parameter :: y=a + end subroutine + end module + """ + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[1] + rbbl = ReplaceReferenceByLiteralTrans() + rbbl.apply(foo) + written_code = fortran_writer(foo.ancestor(Container)) + print(written_code) + assert ( + "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found a" + in written_code + ) + assert "integer, parameter :: x = a" in written_code + assert "integer, parameter :: a = 2" in written_code + assert "integer, parameter :: y = a" in written_code + + +def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): + """test fortran code annotation with transformation warning and + value is coming from the closest scope. + """ + + source = """module toto + integer, parameter :: a=3 +contains + subroutine tata() + call foo() + end subroutine + subroutine foo() + integer, parameter :: a=2 + integer, dimension(10, a) :: array + end subroutine + end module + """ + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[1] + rbbl = ReplaceReferenceByLiteralTrans() + rbbl.apply(foo) + written_code = fortran_writer(foo.ancestor(Container)) + assert ( + "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found" + in written_code + ) + assert "integer, dimension(10,2) :: array" in written_code + + def test_rrbl_write_fortran_comment_warning_about_symbol_found( fortran_reader, fortran_writer ): From 4b61ea084b7b91a1188da1a2c2922a3484f9d9ea Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:10:37 +0100 Subject: [PATCH 17/25] #2828 user friendly comment --- .../transformations/replace_reference_by_literal_trans.py | 7 ++++--- .../replace_reference_by_literal_trans_test.py | 5 +++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index fb5f2fd34d..bdd2dc083d 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -166,9 +166,10 @@ def _update_param_table( param_table.pop(sym_name) if not isinstance(sym.initial_value, Literal): message = ( - "Psyclone(ReplaceReferenceByLiteralTrans): " - + f"DataSymbol {sym_name} initial value is not " - + f"a Literal {type(sym.initial_value)}." + "Psyclone(ReplaceReferenceByLiteral): only " + + "supports symbols which have a Literal as their " + + f"initial value but {sym_name} is assigned " + + f"a {type(sym.initial_value)}" ) sym.preceding_comment += message new_literal: Literal = sym.initial_value.copy().detach() diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 7ce41a6f74..96b106eae0 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -322,7 +322,7 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( rbbl.apply(foo) written_code = fortran_writer(foo.ancestor(Container)) assert ( - "Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol b initial value is not a Literal" + "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which have a Literal as their initial value" in written_code ) @@ -348,7 +348,8 @@ def test_rrbl_raise_transformation_error_initial_value( rbbl = ReplaceReferenceByLiteralTrans() rbbl.apply(foo) written_code = fortran_writer(foo.ancestor(Container)) + print(written_code) assert ( - "! Psyclone(ReplaceReferenceByLiteralTrans): DataSymbol b initial value is not a Literal" + "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which have a Literal as their initial value" in written_code ) From 1e6089fc4e1d0f06856e802fa30004c038855530 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:13:19 +0100 Subject: [PATCH 18/25] #2828 missing docstring --- .../replace_reference_by_literal_trans.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index bdd2dc083d..77440e59d0 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -181,6 +181,17 @@ def _replace_bounds( current_shape: List[Union[Literal, Reference]], param_table: Dict[str, Literal], ) -> List[Union[Literal, Reference]]: + """From the param_table and the current_shape of an array, + this method create a new_shape with the reference replaced by literal + when they are found in the param_table. + + :param current_shape: shape before transformation + :type current_shape: List[Union[Literal, Reference]] + :param param_table: table of parameters Literal values. + :type param_table: Dict[str, Literal] + :return: the new shape with replaced reference by literal. + :rtype: List[Union[Literal, Reference]] + """ new_shape = [] for dim in current_shape: if isinstance(dim, ArrayType.ArrayBounds): From 880ce34d4ca1cbc36787009a5f4829a4fd3d1ad3 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:29:09 +0100 Subject: [PATCH 19/25] #2828 docstrings --- .../replace_reference_by_literal_trans.py | 53 ++++++++++++------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 77440e59d0..1ae1a0e732 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -49,8 +49,8 @@ from psyclone.psyir.symbols import ( ArrayType, DataSymbol, - Symbol, SymbolTable, + UnsupportedFortranType, ) from psyclone.psyir.transformations.transformation_error import ( TransformationError, @@ -126,6 +126,8 @@ class ReplaceReferenceByLiteralTrans(Transformation): def __init__(self) -> None: super().__init__() + # Dictionary with Literal values of the corresponding symbol + # from symbol_table (based on symbol name as a string). self._param_table: Dict[str, Literal] = {} def _update_param_table( @@ -144,9 +146,7 @@ def _update_param_table( * Returns the updated param_table :param param_table: To be updated - :type param_table: Dict[str, Literal] :param symbol_table: scope symbol table to look for the symbols. - :type symbol_table: SymbolTable :return: the updated param_table (same reference as the entry one) :rtype: Dict[str, Literal] """ @@ -186,11 +186,8 @@ def _replace_bounds( when they are found in the param_table. :param current_shape: shape before transformation - :type current_shape: List[Union[Literal, Reference]] :param param_table: table of parameters Literal values. - :type param_table: Dict[str, Literal] :return: the new shape with replaced reference by literal. - :rtype: List[Union[Literal, Reference]] """ new_shape = [] for dim in current_shape: @@ -215,12 +212,32 @@ def _replace_bounds( # ------------------------------------------------------------------------ def apply(self, node: Routine, options=None): + """Applies the transformation to a Routine node: + * First update a dictionary (param_table) with the Literal of constant + (parameter) symbol from node.parent symbol_table, and from + node.symbol_table. + * Second, use this updated param_table to replace reference in node + psyir_tree with the corresponsing Literal. + * Third, use this updated param_table to replace reference in node + symbol_table DataSymbol array's dimensions with the corresponsing + Literal. + + :param node: _description_ + :param options: not used, defaults to None + :type options: _type_, optional + """ self.validate(node, options) - if isinstance(node.parent, Container): - self._param_table = self._update_param_table( - self._param_table, node.parent.symbol_table - ) + ## NOTE: (From Andrew) We may want to look at all symbols in scope + # rather than just those in the parent symbol table? + if node.parent is not None and isinstance(node.parent, Container): + if node.parent.symbol_table is not None: + self._param_table = self._update_param_table( + self._param_table, node.parent.symbol_table + ) + ## NOTE: and other parent scopes? + # symbol_table.parent_symbol_table + ## node.symbol_table is not None (in validate) self._param_table = self._update_param_table( self._param_table, node.symbol_table ) @@ -231,13 +248,9 @@ def apply(self, node: Routine, options=None): literal: Literal = self._param_table[ref.name] ref.replace_with(literal.copy()) - for sym in node.symbol_table.symbols: - sym: Symbol - if isinstance(sym, DataSymbol) and sym.is_array: - from psyclone.psyir.symbols.datatypes import ( - UnsupportedFortranType, - ) - + for sym in node.symbol_table.datasymbols: + sym: DataSymbol + if sym.is_array: if not isinstance(sym.datatype, UnsupportedFortranType): new_shape: List[Union[Literal, Reference]] = ( self._replace_bounds(sym.shape, self._param_table) @@ -251,11 +264,11 @@ def validate(self, node, options=None): Node. :param node: the node that is being checked. - :type node: :py:class:`psyclone.psyir.nodes.Routine` - + :param options: not used, defaults to None + :type options: _type_, optional :raises TransformationError: if the node argument is not a \ Routine. - + :raises TransformationError: if the symbol_table is None """ if not isinstance(node, Routine): raise TransformationError( From 113565ee7bfc4267aa1c71cc0a65dd6670b0b7d1 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:48:29 +0100 Subject: [PATCH 20/25] #2828 cover more edge cases. --- .../replace_reference_by_literal_trans.py | 10 +-- ...replace_reference_by_literal_trans_test.py | 71 +++++++++++-------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 1ae1a0e732..4d0876a8cb 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -164,6 +164,7 @@ def _update_param_table( ) sym.preceding_comment += message param_table.pop(sym_name) + continue if not isinstance(sym.initial_value, Literal): message = ( "Psyclone(ReplaceReferenceByLiteral): only " @@ -172,6 +173,7 @@ def _update_param_table( + f"a {type(sym.initial_value)}" ) sym.preceding_comment += message + continue new_literal: Literal = sym.initial_value.copy().detach() param_table[sym_name] = new_literal return param_table @@ -226,6 +228,8 @@ def apply(self, node: Routine, options=None): :param options: not used, defaults to None :type options: _type_, optional """ + ## Reset the param table for the current Routine + self._param_table = {} self.validate(node, options) ## NOTE: (From Andrew) We may want to look at all symbols in scope # rather than just those in the parent symbol table? @@ -266,9 +270,7 @@ def validate(self, node, options=None): :param node: the node that is being checked. :param options: not used, defaults to None :type options: _type_, optional - :raises TransformationError: if the node argument is not a \ - Routine. - :raises TransformationError: if the symbol_table is None + :raises TransformationError: if the node argument is not a Routine. """ if not isinstance(node, Routine): raise TransformationError( @@ -276,8 +278,6 @@ def validate(self, node, options=None): f"argument should be a PSyIR Routine, but found " f"'{type(node).__name__}'." ) - if node.symbol_table is None: - raise TransformationError("SymbolTable is None") __all__ = ["ReplaceReferenceByLiteralTrans"] diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 96b106eae0..5091aa837f 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -52,11 +52,6 @@ def test_rrbl_general(): """Test general functionality of the transformation.""" rrbl = ReplaceReferenceByLiteralTrans() - - assert ( - "psyclone.psyir.transformations.replace_reference_by_literal_trans.ReplaceReferenceByLiteralTrans" - in str(rrbl) - ) assert rrbl.name == "ReplaceReferenceByLiteralTrans" @@ -78,18 +73,22 @@ def test_rrbl_errors(): # ---------------------------------------------------------------------------- def test_rrbl_in_loop(fortran_reader, fortran_writer): - """Tests if subroutine parameters are replaced as expected.""" + """Tests if subroutine parameters are replaced as expected. + * constant var in a loop bound, e.g. do i = u1, u4, u1 + * constant var as index in derived-type access, e.g. t1%b(u4) + """ source = """program test use mymod type(my_type):: t1, t2, t3, t4 integer, parameter :: x=3, y=12, z=13 - integer, parameter :: u1=1, u2=2, u3=3, u4=4 + integer, parameter :: u1=1, u2=2, u3=3, u4=4, u10=10 integer i, invariant, ic1, ic2, ic3 real, dimension(10) :: a invariant = 1 - do i = 1, 10 + do i = u1, u10, u1 t1%a = z + t1%b(u4) = y a(ic1) = u1+(ic1+x)*ic1 a(ic2) = u2+(ic2+y)*ic2 a(ic3) = u3+(ic3+z)*ic3 @@ -198,28 +197,6 @@ def test_rrbl_array_type_extend(fortran_reader, fortran_writer): assert "integer, dimension(:,3:)" in written_code -def test_rrbl_raise_transformation_error_symbol_table_is_none( - fortran_reader, fortran_writer -): - """test raise TransformationError because of None value in SymbolTable""" - - source = """subroutine foo() - integer, parameter :: a = 3 - integer :: x - x = a - end subroutine""" - psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] - foo._symbol_table = None - rbbl = ReplaceReferenceByLiteralTrans() - error_str = "" - try: - rbbl.apply(foo) - except TransformationError as e: - error_str = e.__str__() - assert "SymbolTable is None" in error_str - - def test_rrbl_conflict_between_module_and_routine_scopes( fortran_reader, fortran_writer ): @@ -253,15 +230,46 @@ def test_rrbl_conflict_between_module_and_routine_scopes( assert "integer, parameter :: y = a" in written_code +def test_rrbl_call_with_const(fortran_reader, fortran_writer): + """ + * constant var as argument to subroutine call, e.g. call my_sub(ic1+u3) + """ + + source = """module toto + integer, parameter :: a=3, u2=2 +contains + subroutine tata() + integer :: i + integer, parameter :: u3=3 + do i=1,10,1 + call foo(u2+ u3) + enddo + end subroutine + subroutine foo() + integer, dimension(10, a) :: array + end subroutine + end module + """ + psyir = fortran_reader.psyir_from_source(source) + foo: Routine = psyir.walk(Routine)[0] + rbbl = ReplaceReferenceByLiteralTrans() + rbbl.apply(foo) + written_code = fortran_writer(foo.ancestor(Container)) + assert "integer, dimension(10,a) :: array" in written_code + assert "call foo(2 + 3)" in written_code + + def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): """test fortran code annotation with transformation warning and value is coming from the closest scope. + * constant var as argument to subroutine call, e.g. call my_sub(ic1+u3) """ source = """module toto integer, parameter :: a=3 contains subroutine tata() + integer :: i call foo() end subroutine subroutine foo() @@ -279,7 +287,7 @@ def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found" in written_code ) - assert "integer, dimension(10,2) :: array" in written_code + assert "integer, dimension(10,a) :: array" in written_code def test_rrbl_write_fortran_comment_warning_about_symbol_found( @@ -325,6 +333,7 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which have a Literal as their initial value" in written_code ) + assert "x = b" in written_code def test_rrbl_raise_transformation_error_initial_value( From 1a549223f428a4a5249d8795cf2cad6203cd6992 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:49:20 +0100 Subject: [PATCH 21/25] #2828 remove outdated comment --- .../transformations/replace_reference_by_literal_trans_test.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 5091aa837f..d229680603 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -96,7 +96,6 @@ def test_rrbl_in_loop(fortran_reader, fortran_writer): end do end program test""" psyir = fortran_reader.psyir_from_source(source) - # The first child is the assignment to 'invariant' routine = psyir.walk(Routine)[0] rrbl = ReplaceReferenceByLiteralTrans() rrbl.apply(routine) @@ -164,7 +163,6 @@ def test_rrbl_array_shape(fortran_reader, fortran_writer): end subroutine """ psyir = fortran_reader.psyir_from_source(source) - # The first child is the assignment to 'invariant' mainprog = psyir.walk(Routine)[0] routine_testfalse = psyir.walk(Routine)[1] rrbl = ReplaceReferenceByLiteralTrans() From 517682a2a6702f376ceb1ef28843d29b56012555 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 16:56:46 +0100 Subject: [PATCH 22/25] #2828 minor cleaning --- ...replace_reference_by_literal_trans_test.py | 23 ++++--------------- 1 file changed, 5 insertions(+), 18 deletions(-) diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index d229680603..00702b2eda 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -40,22 +40,18 @@ import pytest from psyclone.psyir.nodes import Container, Literal, Routine -from psyclone.psyir.symbols import INTEGER_TYPE +from psyclone.psyir.symbols import DataSymbol, INTEGER_TYPE from psyclone.psyir.transformations import ( ReplaceReferenceByLiteralTrans, TransformationError, ) - -# ---------------------------------------------------------------------------- def test_rrbl_general(): """Test general functionality of the transformation.""" rrbl = ReplaceReferenceByLiteralTrans() assert rrbl.name == "ReplaceReferenceByLiteralTrans" - -# ---------------------------------------------------------------------------- def test_rrbl_errors(): """Test errors that should be thrown.""" @@ -70,8 +66,6 @@ def test_rrbl_errors(): "'Literal'" in str(err.value) ) - -# ---------------------------------------------------------------------------- def test_rrbl_in_loop(fortran_reader, fortran_writer): """Tests if subroutine parameters are replaced as expected. * constant var in a loop bound, e.g. do i = u1, u4, u1 @@ -105,7 +99,6 @@ def test_rrbl_in_loop(fortran_reader, fortran_writer): assert "a(ic3) = 3 + (ic3 + 13) * ic3" in written_code assert "a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a" in written_code - def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): """test replacement of reference by a literal defined as constant value in the module scope @@ -132,9 +125,10 @@ def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): assert "a(ic1) = 1 + (ic1 + 2) * ic1 * 3" in out - def test_rrbl_array_shape(fortran_reader, fortran_writer): - """Tests if subroutine parameters are replaced as expected.""" + """Tests if subroutine parameters are replaced as expected when they appear + in array shape specifications or logical expressions. + """ source = """subroutine testtrue() logical, parameter :: x=.true., y=.false. @@ -179,7 +173,7 @@ def test_rrbl_array_shape(fortran_reader, fortran_writer): assert "if (.false.) then" in written_code -def test_rrbl_array_type_extend(fortran_reader, fortran_writer): +def test_rrbl_array_type_extent(fortran_reader, fortran_writer): """test replacement of lower bound of an array dimension""" source = """subroutine foo() @@ -256,7 +250,6 @@ def test_rrbl_call_with_const(fortran_reader, fortran_writer): assert "integer, dimension(10,a) :: array" in written_code assert "call foo(2 + 3)" in written_code - def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): """test fortran code annotation with transformation warning and value is coming from the closest scope. @@ -287,7 +280,6 @@ def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): ) assert "integer, dimension(10,a) :: array" in written_code - def test_rrbl_write_fortran_comment_warning_about_symbol_found( fortran_reader, fortran_writer ): @@ -309,7 +301,6 @@ def test_rrbl_write_fortran_comment_warning_about_symbol_found( in written_code ) - def test_rrbl_raise_transformation_error_initial_value_not_literal( fortran_reader, fortran_writer ): @@ -322,7 +313,6 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( end subroutine""" psyir = fortran_reader.psyir_from_source(source) foo: Routine = psyir.walk(Routine)[0] - assert foo.symbol_table is not None rbbl = ReplaceReferenceByLiteralTrans() rbbl.apply(foo) @@ -333,7 +323,6 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( ) assert "x = b" in written_code - def test_rrbl_raise_transformation_error_initial_value( fortran_reader, fortran_writer ): @@ -347,8 +336,6 @@ def test_rrbl_raise_transformation_error_initial_value( end subroutine""" psyir = fortran_reader.psyir_from_source(source) foo: Routine = psyir.walk(Routine)[0] - assert foo.symbol_table is not None - from psyclone.psyir.symbols import DataSymbol sym_a: DataSymbol = foo.symbol_table.find_or_create("a") assert not sym_a.is_constant From 207cda3b2102c4e74e012bc006016ce1a48eadc7 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Mon, 20 Jan 2025 17:27:30 +0100 Subject: [PATCH 23/25] #2828 fix sphinx make html --- .../replace_reference_by_literal_trans.py | 35 ++++++++++--------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 4d0876a8cb..c19e423bdc 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -68,21 +68,21 @@ class ReplaceReferenceByLiteralTrans(Transformation): >>> from psyclone.psyir.symbols import INTEGER_TYPE >>> from psyclone.psyir.transformations import ReplaceReferenceByLiteralTrans >>> source = """program test - ... use mymod - ... type(my_type):: t1, t2, t3, t4 - ... integer, parameter :: x=3, y=12, z=13 - ... integer, parameter :: u1=1, u2=2, u3=3, u4=4 - ... integer i, invariant, ic1, ic2, ic3 - ... real, dimension(10) :: a - ... invariant = 1 - ... do i = 1, 10 - ... t1%a = z - ... a(ic1) = u1+(ic1+x)*ic1 - ... a(ic2) = u2+(ic2+y)*ic2 - ... a(ic3) = u3+(ic3+z)*ic3 - ... a(t1%a) = u4+(t1%a+u4*z)*t1%a - ... end do - ... end program test""" + ... use mymod + ... type(my_type):: t1, t2, t3, t4 + ... integer, parameter :: x=3, y=12, z=13 + ... integer, parameter :: u1=1, u2=2, u3=3, u4=4 + ... integer i, invariant, ic1, ic2, ic3 + ... real, dimension(10) :: a + ... invariant = 1 + ... do i = 1, 10 + ... t1%a = z + ... a(ic1) = u1+(ic1+x)*ic1 + ... a(ic2) = u2+(ic2+y)*ic2 + ... a(ic3) = u3+(ic3+z)*ic3 + ... a(t1%a) = u4+(t1%a+u4*z)*t1%a + ... end do + ... end program test""" >>> fortran_writer = FortranWriter() >>> fortran_reader = FortranReader() >>> psyir = fortran_reader.psyir_from_source(source) @@ -110,7 +110,7 @@ class ReplaceReferenceByLiteralTrans(Transformation): integer :: ic2 integer :: ic3 real, dimension(10) :: a - + invariant = 1 do i = 1, 10, 1 t1%a = 13 @@ -119,8 +119,9 @@ class ReplaceReferenceByLiteralTrans(Transformation): a(ic3) = 3 + (ic3 + 13) * ic3 a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a enddo - + end program test + ''' From b1347747e5410e9b57951cbec9214056ba5dbdab Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Thu, 23 Jan 2025 10:28:54 +0100 Subject: [PATCH 24/25] #2828 fix flake8 --- .../replace_reference_by_literal_trans.py | 6 +- ...replace_reference_by_literal_trans_test.py | 73 +++++++++++-------- 2 files changed, 46 insertions(+), 33 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index c19e423bdc..8f5e2d178e 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -33,7 +33,7 @@ # ----------------------------------------------------------------------------- # Author: H. Brunie, University of Grenoble Alpes -"""Module providing a transformation that replace PsyIR Node representing a +"""Module providing a transformation that replace PsyIR Node representing a static, constant value with a Literal Node when possible. """ from typing import Dict, List, Union @@ -56,6 +56,7 @@ TransformationError, ) + class ReplaceReferenceByLiteralTrans(Transformation): ''' This transformation takes a psyir Routine and replace all Reference psyir @@ -66,7 +67,8 @@ class ReplaceReferenceByLiteralTrans(Transformation): >>> from psyclone.psyir.backend.fortran import FortranWriter >>> from psyclone.psyir.symbols import INTEGER_TYPE - >>> from psyclone.psyir.transformations import ReplaceReferenceByLiteralTrans + >>> from psyclone.psyir.transformations import ( + ReplaceReferenceByLiteralTrans) >>> source = """program test ... use mymod ... type(my_type):: t1, t2, t3, t4 diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 00702b2eda..23f39b8b99 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -46,12 +46,14 @@ TransformationError, ) + def test_rrbl_general(): """Test general functionality of the transformation.""" rrbl = ReplaceReferenceByLiteralTrans() assert rrbl.name == "ReplaceReferenceByLiteralTrans" + def test_rrbl_errors(): """Test errors that should be thrown.""" @@ -66,6 +68,7 @@ def test_rrbl_errors(): "'Literal'" in str(err.value) ) + def test_rrbl_in_loop(fortran_reader, fortran_writer): """Tests if subroutine parameters are replaced as expected. * constant var in a loop bound, e.g. do i = u1, u4, u1 @@ -99,6 +102,7 @@ def test_rrbl_in_loop(fortran_reader, fortran_writer): assert "a(ic3) = 3 + (ic3 + 13) * ic3" in written_code assert "a(t1%a) = 4 + (t1%a + 4 * 13) * t1%a" in written_code + def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): """test replacement of reference by a literal defined as constant value in the module scope @@ -125,6 +129,7 @@ def test_rrbl_module_defined_parameter(fortran_reader, fortran_writer): assert "a(ic1) = 1 + (ic1 + 2) * ic1 * 3" in out + def test_rrbl_array_shape(fortran_reader, fortran_writer): """Tests if subroutine parameters are replaced as expected when they appear in array shape specifications or logical expressions. @@ -181,10 +186,10 @@ def test_rrbl_array_type_extent(fortran_reader, fortran_writer): integer, dimension(:,a:) :: x end subroutine""" psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] + routine_foo: Routine = psyir.walk(Routine)[0] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo) assert "integer, dimension(:,3:)" in written_code @@ -196,7 +201,7 @@ def test_rrbl_conflict_between_module_and_routine_scopes( source = """module toto integer, parameter :: a=3 -contains +contains subroutine tata() call foo() end subroutine @@ -205,13 +210,13 @@ def test_rrbl_conflict_between_module_and_routine_scopes( integer, parameter :: a=2 integer, parameter :: y=a end subroutine - end module + end module """ psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[1] + routine_foo: Routine = psyir.walk(Routine)[1] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo.ancestor(Container)) print(written_code) assert ( "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found a" @@ -229,7 +234,7 @@ def test_rrbl_call_with_const(fortran_reader, fortran_writer): source = """module toto integer, parameter :: a=3, u2=2 -contains +contains subroutine tata() integer :: i integer, parameter :: u3=3 @@ -240,16 +245,17 @@ def test_rrbl_call_with_const(fortran_reader, fortran_writer): subroutine foo() integer, dimension(10, a) :: array end subroutine - end module + end module """ psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] + routine_foo: Routine = psyir.walk(Routine)[0] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo.ancestor(Container)) assert "integer, dimension(10,a) :: array" in written_code assert "call foo(2 + 3)" in written_code + def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): """test fortran code annotation with transformation warning and value is coming from the closest scope. @@ -258,7 +264,7 @@ def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): source = """module toto integer, parameter :: a=3 -contains +contains subroutine tata() integer :: i call foo() @@ -267,19 +273,20 @@ def test_rrbl_same_constant_data_symbol_twice(fortran_reader, fortran_writer): integer, parameter :: a=2 integer, dimension(10, a) :: array end subroutine - end module + end module """ psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[1] + routine_foo: Routine = psyir.walk(Routine)[1] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo.ancestor(Container)) assert ( "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found" in written_code ) assert "integer, dimension(10,a) :: array" in written_code + def test_rrbl_write_fortran_comment_warning_about_symbol_found( fortran_reader, fortran_writer ): @@ -291,16 +298,17 @@ def test_rrbl_write_fortran_comment_warning_about_symbol_found( x = a end subroutine""" psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] + routine_foo: Routine = psyir.walk(Routine)[0] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - rbbl._update_param_table(rbbl._param_table, foo.symbol_table) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + rbbl._update_param_table(rbbl._param_table, routine_foo.symbol_table) + written_code = fortran_writer(routine_foo.ancestor(Container)) assert ( "! Psyclone(ReplaceReferenceByLiteralTrans): Symbol already found" in written_code ) + def test_rrbl_raise_transformation_error_initial_value_not_literal( fortran_reader, fortran_writer ): @@ -312,17 +320,19 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( x = b end subroutine""" psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] + routine_foo: Routine = psyir.walk(Routine)[0] rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo.ancestor(Container)) assert ( - "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which have a Literal as their initial value" + "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which" + + "have a Literal as their initial value" in written_code ) assert "x = b" in written_code + def test_rrbl_raise_transformation_error_initial_value( fortran_reader, fortran_writer ): @@ -335,15 +345,16 @@ def test_rrbl_raise_transformation_error_initial_value( x = a end subroutine""" psyir = fortran_reader.psyir_from_source(source) - foo: Routine = psyir.walk(Routine)[0] + routine_foo: Routine = psyir.walk(Routine)[0] - sym_a: DataSymbol = foo.symbol_table.find_or_create("a") + sym_a: DataSymbol = routine_foo.symbol_table.find_or_create("a") assert not sym_a.is_constant rbbl = ReplaceReferenceByLiteralTrans() - rbbl.apply(foo) - written_code = fortran_writer(foo.ancestor(Container)) + rbbl.apply(routine_foo) + written_code = fortran_writer(routine_foo.ancestor(Container)) print(written_code) assert ( - "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which have a Literal as their initial value" + "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which" + + " have a Literal as their initial value" in written_code ) From 725b03d20736a535140edcae870a0e25fc5dced1 Mon Sep 17 00:00:00 2001 From: Hugo Brunie Date: Thu, 23 Jan 2025 13:25:10 +0100 Subject: [PATCH 25/25] #2828 introducing cls constant for test avoid error prone string comparison --- .../replace_reference_by_literal_trans.py | 14 +++++++++++--- .../replace_reference_by_literal_trans_test.py | 6 +----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py index 8f5e2d178e..bd86db1bd1 100644 --- a/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py +++ b/src/psyclone/psyir/transformations/replace_reference_by_literal_trans.py @@ -127,6 +127,11 @@ class ReplaceReferenceByLiteralTrans(Transformation): ''' + _ERROR_MSG = ( + "Psyclone(ReplaceReferenceByLiteral): only " + + "supports symbols which have a Literal as their initial value but " + ) + def __init__(self) -> None: super().__init__() # Dictionary with Literal values of the corresponding symbol @@ -157,6 +162,9 @@ def _update_param_table( sym: DataSymbol if sym.is_constant: sym_name = sym.name + print(sym_name) + print(type(sym.initial_value)) + print(param_table.get(sym_name)) if param_table.get(sym_name): message = ( "Psyclone(ReplaceReferenceByLiteralTrans):" @@ -170,12 +178,12 @@ def _update_param_table( continue if not isinstance(sym.initial_value, Literal): message = ( - "Psyclone(ReplaceReferenceByLiteral): only " - + "supports symbols which have a Literal as their " - + f"initial value but {sym_name} is assigned " + ReplaceReferenceByLiteralTrans._ERROR_MSG + + f"{sym_name} is assigned " + f"a {type(sym.initial_value)}" ) sym.preceding_comment += message + print(sym.preceding_comment) continue new_literal: Literal = sym.initial_value.copy().detach() param_table[sym_name] = new_literal diff --git a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py index 23f39b8b99..aab7b15158 100644 --- a/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py +++ b/src/psyclone/tests/psyir/transformations/replace_reference_by_literal_trans_test.py @@ -325,11 +325,7 @@ def test_rrbl_raise_transformation_error_initial_value_not_literal( rbbl = ReplaceReferenceByLiteralTrans() rbbl.apply(routine_foo) written_code = fortran_writer(routine_foo.ancestor(Container)) - assert ( - "! Psyclone(ReplaceReferenceByLiteral): only supports symbols which" - + "have a Literal as their initial value" - in written_code - ) + assert ReplaceReferenceByLiteralTrans._ERROR_MSG in written_code assert "x = b" in written_code