From 6c3c9d22743b208fc1750dc5d989094881be4819 Mon Sep 17 00:00:00 2001 From: Maurice Jamieson Date: Sun, 3 Mar 2024 16:31:10 +0000 Subject: [PATCH] Initial commit --- examples/xdsl/README.txt | 3 + examples/xdsl/eg1/create.py | 118 +++ examples/xdsl/eg2/create.py | 133 ++++ examples/xdsl/eg3/create.py | 147 ++++ examples/xdsl/eg4/create.py | 162 +++++ examples/xdsl/eg4/create_2.py | 168 +++++ examples/xdsl/eg5/create.py | 216 ++++++ examples/xdsl/tra_adv/README.md | 63 ++ examples/xdsl/tra_adv/adv_reduced.F90 | 103 +++ .../pw_advection/advection_heap.F90 | 83 +++ .../benchmarks/pw_advection/advection_mpi.F90 | 182 +++++ .../pw_advection/advection_mpi_orig.F90 | 137 ++++ .../pw_advection/advection_stack.F90 | 59 ++ .../tra_adv/benchmarks/tra_adv/simple.F90 | 8 + .../benchmarks/tra_adv/tra_adv_heap.F90 | 263 +++++++ .../benchmarks/tra_adv/tra_adv_mpi.F90 | 280 ++++++++ .../benchmarks/tra_adv/tra_adv_stack.F90 | 216 ++++++ .../xdsl/tra_adv/code_sample/array_test.F90 | 42 ++ .../xdsl/tra_adv/code_sample/gauss_seidel.F90 | 32 + .../xdsl/tra_adv/code_sample/mpi_test.F90 | 67 ++ .../xdsl/tra_adv/code_sample/mpi_test3.F90 | 42 ++ .../xdsl/tra_adv/code_sample/mpi_test4.F90 | 40 ++ .../xdsl/tra_adv/code_sample/mpi_test_2.F90 | 33 + .../xdsl/tra_adv/code_sample/timing_test.F90 | 13 + .../xdsl/tra_adv/xdsl_backends_transform.py | 93 +++ src/psyclone/psyir/backend/language_writer.py | 2 +- src/psyclone/psyir/backend/xdsl.py | 680 ++++++++++++++++++ src/psyclone/psyir/nodes/__init__.py | 3 +- src/psyclone/psyir/nodes/operation.py | 178 ++++- .../infrastructure/field/field_mod.f90 | 14 +- .../field/master_dofmap_mod.f90 | 2 - .../field/quadrature_face_mod.f90 | 2 - .../infrastructure/field/quadrature_mod.f90 | 2 - .../field/quadrature_rule_mod.f90 | 2 - .../field/quadrature_xoyoz_mod.f90 | 2 - .../field/quadrature_xyoz_mod.f90 | 2 - .../field/quadrature_xyz_mod.f90 | 2 - .../infrastructure/field/r_phys_field_mod.f90 | 14 +- .../field/r_solver_field_mod.f90 | 14 +- .../infrastructure/field/r_tran_field_mod.f90 | 14 +- .../field/stencil_dofmap_mod.f90 | 2 - ...space_constructor_helper_functions_mod.f90 | 2 - .../infrastructure/io/ugrid_2d_mod.f90 | 2 - .../infrastructure/io/ugrid_file_mod.f90 | 2 - .../mesh/global_mesh_base_mod.f90 | 2 - .../infrastructure/mesh/mesh_mod.f90 | 2 - .../infrastructure/operator/operator_mod.f90 | 12 +- .../operator/r_solver_operator_mod.f90 | 12 +- .../infrastructure/scalar/scalar_mod.f90 | 10 +- .../utilities/linked_list_mod.f90 | 2 - .../infrastructure/utilities/timer_mod.f90 | 2 - 51 files changed, 3599 insertions(+), 87 deletions(-) create mode 100644 examples/xdsl/README.txt create mode 100644 examples/xdsl/eg1/create.py create mode 100644 examples/xdsl/eg2/create.py create mode 100644 examples/xdsl/eg3/create.py create mode 100644 examples/xdsl/eg4/create.py create mode 100644 examples/xdsl/eg4/create_2.py create mode 100644 examples/xdsl/eg5/create.py create mode 100644 examples/xdsl/tra_adv/README.md create mode 100644 examples/xdsl/tra_adv/adv_reduced.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/pw_advection/advection_heap.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi_orig.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/pw_advection/advection_stack.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/tra_adv/simple.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_heap.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_mpi.F90 create mode 100644 examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_stack.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/array_test.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/gauss_seidel.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/mpi_test.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/mpi_test3.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/mpi_test4.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/mpi_test_2.F90 create mode 100644 examples/xdsl/tra_adv/code_sample/timing_test.F90 create mode 100644 examples/xdsl/tra_adv/xdsl_backends_transform.py create mode 100644 src/psyclone/psyir/backend/xdsl.py diff --git a/examples/xdsl/README.txt b/examples/xdsl/README.txt new file mode 100644 index 00000000000..8e336601c16 --- /dev/null +++ b/examples/xdsl/README.txt @@ -0,0 +1,3 @@ +These examples generate simple PsyIR that is then fed into the XDSL writer backend and translated to xDSL PSyclone dialect, with these you can run via: + +e.g. python 3.10 create.py \ No newline at end of file diff --git a/examples/xdsl/eg1/create.py b/examples/xdsl/eg1/create.py new file mode 100644 index 00000000000..70c579cd950 --- /dev/null +++ b/examples/xdsl/eg1/create.py @@ -0,0 +1,118 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which creates a simple assignment and variables + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code +''' + +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) + scalar_symbol = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + # Binary Operation + oper = BinaryOperation.Operator.ADD + binaryoperation = BinaryOperation.create(oper, one(), two()) + + # Assignments + assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + + # Routine + routine = Routine.create("work", symbol_table, [assign1]) + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("work") + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + call = Call.create(work_symbol, []) + program = Routine.create("some_program", program_symbol_table, [call], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) diff --git a/examples/xdsl/eg2/create.py b/examples/xdsl/eg2/create.py new file mode 100644 index 00000000000..050df3341a4 --- /dev/null +++ b/examples/xdsl/eg2/create.py @@ -0,0 +1,133 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project. +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which creates a conditional and simple variables +and datatypes + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code +''' + +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) + scalar_symbol = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + + tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol, + datatype=REAL_TYPE) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def zero(): + return Literal("0.0", REAL_TYPE) + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def onert(): + return Literal("1.0", REAL_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + # Binary Operation + oper = BinaryOperation.Operator.ADD + binaryoperation = BinaryOperation.create(oper, one(), two()) + + # Assignments + assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + assign2 = Assignment.create(Reference(tmp_symbol), zero()) + assign3 = Assignment.create(Reference(scalar_symbol), two()) + + if_condition = BinaryOperation.create(BinaryOperation.Operator.EQ, + Reference(tmp_symbol), onert()) + ifblock = IfBlock.create(if_condition, [assign3]) + + # Routine + routine = Routine.create("work", symbol_table, [assign1, assign2, ifblock]) + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("work") + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + call = Call.create(work_symbol, []) + program = Routine.create("some_program", program_symbol_table, [call], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) diff --git a/examples/xdsl/eg3/create.py b/examples/xdsl/eg3/create.py new file mode 100644 index 00000000000..bcf84f11b7d --- /dev/null +++ b/examples/xdsl/eg3/create.py @@ -0,0 +1,147 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which creates a conditional, loop and simple variables +and datatypes + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code +''' + +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) + scalar_symbol = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + + tmp_symbol = symbol_table.new_symbol(symbol_type=DataSymbol, + datatype=REAL_TYPE) + + index_symbol = symbol_table.new_symbol(root_name="i", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def zero(): + return Literal("0.0", REAL_TYPE) + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def onert(): + return Literal("1.0", REAL_TYPE) + + def int_zero(): + return Literal("0", INTEGER_SINGLE_TYPE) + + def int_one(): + return Literal("1", INTEGER8_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + # Binary Operation + oper = BinaryOperation.Operator.ADD + binaryoperation = BinaryOperation.create(oper, one(), two()) + + # Assignments + assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + assign2 = Assignment.create(Reference(tmp_symbol), zero()) + assign3 = Assignment.create(Reference(scalar_symbol), two()) + + # Loop + loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(), + [assign3]) + + if_condition = BinaryOperation.create(BinaryOperation.Operator.EQ, + Reference(tmp_symbol), onert()) + ifblock = IfBlock.create(if_condition, [loop]) + + # Routine + routine = Routine.create("work", symbol_table, [assign1, assign2, ifblock]) + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("work") + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + call = Call.create(work_symbol, []) + program = Routine.create("some_program", program_symbol_table, [call], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) diff --git a/examples/xdsl/eg4/create.py b/examples/xdsl/eg4/create.py new file mode 100644 index 00000000000..8b446b40638 --- /dev/null +++ b/examples/xdsl/eg4/create.py @@ -0,0 +1,162 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which builds a subroutine as a function, a loop and +conditional and then generates the xDSL IR along with Fortran code + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code + +''' +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, Return, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + ''' Create an example PSyIR Tree. + + ''' + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) + scalar_symbol = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + + tmp_symbol = symbol_table.new_symbol(root_name="tmp_data", symbol_type=DataSymbol, + datatype=REAL_TYPE) + + index_symbol = symbol_table.new_symbol(root_name="i", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def zero(): + return Literal("0.0", REAL_TYPE) + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def onert(): + return Literal("1.0", REAL_DOUBLE_TYPE) + + def int_zero(): + return Literal("0", INTEGER_SINGLE_TYPE) + + def int_one(): + return Literal("1", INTEGER8_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + # Binary Operation + oper = BinaryOperation.Operator.ADD + binaryoperation = BinaryOperation.create(oper, one(), two()) + + # Unary Operation + uoper = UnaryOperation.Operator.SQRT + unaryoperation=UnaryOperation.create(uoper, onert()) + + # Assignments + assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + assign2 = Assignment.create(Reference(tmp_symbol), onert())) + assign3 = Assignment.create(Reference(scalar_symbol), two()) + + # Loop + loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(), + [assign2]) + + if_condition = BinaryOperation.create(BinaryOperation.Operator.EQ, + Reference(scalar_symbol), int_one()) + + not_condition = UnaryOperation.create(UnaryOperation.Operator.NOT, if_condition) + + ifblock = IfBlock.create(not_condition, [loop]) + + retrn = Return() + + # Routine + routine = Routine.create("work", symbol_table, [assign1, assign3, ifblock, retrn], False, "tmp_data") + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("work", REAL_TYPE) + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + assgn_symbol = program_symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + call = Call.create(work_symbol, []) + assign = Assignment.create(Reference(assgn_symbol), call) + program = Routine.create("some_program", program_symbol_table, [assign], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) + diff --git a/examples/xdsl/eg4/create_2.py b/examples/xdsl/eg4/create_2.py new file mode 100644 index 00000000000..942847d0af9 --- /dev/null +++ b/examples/xdsl/eg4/create_2.py @@ -0,0 +1,168 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which builds a subroutine as a function, a loop and +conditional and then generates the xDSL IR along with Fortran code + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code + +''' +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, Return, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + ''' Create an example PSyIR Tree. + + ''' + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.INTEGER, 4) + scalar_symbol = symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + + tmp_symbol = symbol_table.new_symbol(root_name="tmp_data", symbol_type=DataSymbol, + datatype=REAL_TYPE) + + index_symbol = symbol_table.new_symbol(root_name="i", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + rq_symbol = symbol_table.new_symbol(symbol_type=DataSymbol, + datatype=INTEGER4_TYPE, + interface=ArgumentInterface(ArgumentInterface.Access.READ)) + symbol_table.specify_argument_list([rq_symbol]) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def zero(): + return Literal("0.0", REAL_TYPE) + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def onert(): + return Literal("1.0", REAL_DOUBLE_TYPE) + + def int_zero(): + return Literal("0", INTEGER_SINGLE_TYPE) + + def int_one(): + return Literal("1", INTEGER8_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + # Binary Operation + oper = BinaryOperation.Operator.ADD + binaryoperation = BinaryOperation.create(oper, one(), two()) + + # Unary Operation + uoper = UnaryOperation.Operator.SQRT + unaryoperation=UnaryOperation.create(uoper, onert()) + + # Assignments + assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + assign2 = Assignment.create(Reference(tmp_symbol), onert()) + assign3 = Assignment.create(Reference(scalar_symbol), two()) + + # Loop + loop = Loop.create(index_symbol, int_zero(), int_one(), int_one(), + [assign2]) + + if_condition = BinaryOperation.create(BinaryOperation.Operator.EQ, + Reference(scalar_symbol), int_one()) + + not_condition = UnaryOperation.create(UnaryOperation.Operator.NOT, if_condition) + + ifblock = IfBlock.create(not_condition, [loop]) + + retrn = Return() + + # Routine + routine = Routine.create("work", symbol_table, [assign1, assign3, ifblock, retrn], False, "tmp_data") + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("work", REAL_TYPE) + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + assgn_symbol = program_symbol_table.new_symbol(root_name="a", symbol_type=DataSymbol, datatype=scalar_type) + call = Call.create(work_symbol, [two()]) + assign = Assignment.create(Reference(assgn_symbol), call) + + program = Routine.create("some_program", program_symbol_table, [assign], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) + diff --git a/examples/xdsl/eg5/create.py b/examples/xdsl/eg5/create.py new file mode 100644 index 00000000000..13da4f03c09 --- /dev/null +++ b/examples/xdsl/eg5/create.py @@ -0,0 +1,216 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''An example which builds a subroutine as a function, a loop and +conditional and then generates the xDSL IR along with Fortran code + +Once you have psyclone installed, this script may be run by doing: + +>>> python create.py + +This should output the xDSL IR representation and Fortran code + +''' +from __future__ import print_function +from psyclone.psyir.nodes import Reference, Literal, UnaryOperation, \ + BinaryOperation, NaryOperation, Assignment, IfBlock, Loop, Return, \ + Container, Range, ArrayReference, Call, Routine, FileContainer +from psyclone.psyir.symbols import DataSymbol, RoutineSymbol, SymbolTable, \ + ContainerSymbol, ArgumentInterface, ScalarType, ArrayType, \ + ImportInterface, REAL_TYPE, REAL4_TYPE, REAL_DOUBLE_TYPE, INTEGER_TYPE, \ + INTEGER_SINGLE_TYPE, INTEGER4_TYPE, INTEGER8_TYPE +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.c import CWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +import sys + +def create_psyir_tree(): + ''' Create an example PSyIR Tree. + + ''' + # Symbol table, symbols and scalar datatypes + symbol_table = SymbolTable() + + # Array using precision defined by another symbol + scalar_type = ScalarType(ScalarType.Intrinsic.REAL, 8) + + array_type=ArrayType(scalar_type, [256, 256]) + array_symbol = symbol_table.new_symbol(root_name="data", symbol_type=DataSymbol, datatype=array_type, interface=ArgumentInterface(ArgumentInterface.Access.READWRITE)) + + symbol_table.specify_argument_list([array_symbol]) + + index_i_symbol = symbol_table.new_symbol(root_name="i", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + index_j_symbol = symbol_table.new_symbol(root_name="j", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + index_k_symbol = symbol_table.new_symbol(root_name="k", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + # Make generators for nodes which do not have other Nodes as children, + # with some predefined scalar datatypes + + def zero(): + return Literal("0.0", REAL_TYPE) + + def one(): + return Literal("1", INTEGER_SINGLE_TYPE) + + def float_ten(): + return Literal("10", REAL_DOUBLE_TYPE) + + def loop_max(): + return Literal("255", INTEGER_SINGLE_TYPE) + + def loop_top(): + return Literal("256", INTEGER_SINGLE_TYPE) + + def onert(): + return Literal("1.0", REAL_DOUBLE_TYPE) + + def zerotwofive(): + return Literal("0.25", REAL_DOUBLE_TYPE) + + def int_zero(): + return Literal("0", INTEGER_SINGLE_TYPE) + + def float_one(): + return Literal("1.0", REAL_DOUBLE_TYPE) + + def two(): + return Literal("2", INTEGER_SINGLE_TYPE) + + def num_its(): + return Literal("1000", INTEGER_SINGLE_TYPE) + + # Binary Operation + im1_j=BinaryOperation.create(BinaryOperation.Operator.SUB, Reference(index_i_symbol), one()) + ip1_j=BinaryOperation.create(BinaryOperation.Operator.ADD, Reference(index_i_symbol), one()) + i_jm1=BinaryOperation.create(BinaryOperation.Operator.SUB, Reference(index_j_symbol), one()) + i_jp1=BinaryOperation.create(BinaryOperation.Operator.ADD, Reference(index_j_symbol), one()) + + bop_3=BinaryOperation.create(BinaryOperation.Operator.ADD, ArrayReference.create(array_symbol, [Reference(index_j_symbol), im1_j]), ArrayReference.create(array_symbol, [Reference(index_j_symbol), ip1_j])) + bop_2=BinaryOperation.create(BinaryOperation.Operator.ADD, bop_3, ArrayReference.create(array_symbol, [i_jm1, Reference(index_i_symbol)])) + bop_1=BinaryOperation.create(BinaryOperation.Operator.ADD, bop_2, ArrayReference.create(array_symbol, [i_jp1, Reference(index_i_symbol)])) + binaryoperation = BinaryOperation.create(BinaryOperation.Operator.MUL, bop_1, zerotwofive()) + + # Unary Operation + uoper = UnaryOperation.Operator.SQRT + unaryoperation=UnaryOperation.create(uoper, onert()) + + # Assignments + #assign1 = Assignment.create(Reference(scalar_symbol), binaryoperation) + assign2 = Assignment.create(ArrayReference.create(array_symbol, [Reference(index_j_symbol), Reference(index_i_symbol)]), binaryoperation) + #assign3 = Assignment.create(Reference(scalar_symbol), two()) + + loop_inner = Loop.create(index_j_symbol, two(), loop_max(), one(), + [assign2]) + + # Loop + loop_outer = Loop.create(index_i_symbol, two(), loop_max(), one(), + [loop_inner]) + + loop_its = Loop.create(index_k_symbol, one(), num_its(), one(), + [loop_outer]) + + # Routine + routine = Routine.create("gauss_seidel", symbol_table, [loop_its], False) + + # Container + container_symbol_table = SymbolTable() + container = Container.create("CONTAINER", container_symbol_table, [routine]) + + # Routine (specified as being a program) + program_symbol_table = SymbolTable() + work_symbol = RoutineSymbol("gauss_seidel", REAL_TYPE) + container_symbol = ContainerSymbol("CONTAINER") + work_symbol.interface = ImportInterface(container_symbol) + + program_symbol_table.add(container_symbol) + program_symbol_table.add(work_symbol) + data_symbol = program_symbol_table.new_symbol(root_name="data", symbol_type=DataSymbol, datatype=array_type) + + declaration_index_i_symbol = program_symbol_table.new_symbol(root_name="i", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + declaration_index_j_symbol = program_symbol_table.new_symbol(root_name="j", + symbol_type=DataSymbol, + datatype=INTEGER4_TYPE) + + assign = Assignment.create(ArrayReference.create(data_symbol, [Reference(declaration_index_j_symbol), Reference(declaration_index_i_symbol)]), zero()) + + declaration_loop_inner = Loop.create(declaration_index_j_symbol, two(), loop_max(), one(), + [assign]) + + # Loop + declaration_loop_outer = Loop.create(declaration_index_i_symbol, two(), loop_max(), one(), + [declaration_loop_inner]) + + assign_low_bc = Assignment.create(ArrayReference.create(data_symbol, [Reference(declaration_index_j_symbol), one()]), float_one()) + low_bc_loop=Loop.create(declaration_index_j_symbol, two(), loop_max(), one(), + [assign_low_bc]) + + assign_high_bc = Assignment.create(ArrayReference.create(data_symbol, [Reference(declaration_index_j_symbol), loop_top()]), float_ten()) + assign_high_bc=Loop.create(declaration_index_j_symbol, two(), loop_max(), one(), + [assign_high_bc]) + + call = Call.create(work_symbol, [Reference(data_symbol)]) + #assign = Assignment.create(Reference(assgn_symbol), call) + program = Routine.create("some_program", program_symbol_table, [declaration_loop_outer, low_bc_loop, assign_high_bc, call], is_program=True) + + # File container + file_container = FileContainer.create("dummy", SymbolTable(), [container, program]) + + return file_container + + +if __name__ == "__main__": + psyir_tree = create_psyir_tree() + + writer = xDSLWriter() + result = writer(psyir_tree) + + printer = Printer(stream=sys.stdout) + printer.print_op(result) + + # Write out the code as Fortran + writer = FortranWriter() + result = writer(psyir_tree) + print(result) + diff --git a/examples/xdsl/tra_adv/README.md b/examples/xdsl/tra_adv/README.md new file mode 100644 index 00000000000..c72d254e471 --- /dev/null +++ b/examples/xdsl/tra_adv/README.md @@ -0,0 +1,63 @@ +python3.10 /home/nick/projects/xdsl/PSyclone/bin/psyclone -api nemo -s ./xdsl_backends_transform.py tra_adv.F90 + +To compile, for non-MPI: + +./psy-opt -p apply-stencil-analysis,lower-psy-ir,extract-stencil,rewrite-fir-to-standard psy_output.mlir + +Then copy the module 0 file out to the xdsl tools directory, and run + +./xdsl-opt -p stencil-shape-inference,convert-stencil-to-ll-mlir module_0.mlir -o stencil.mlir + +Then copy stencil.mlir and module_1.mlir (in generated directory) to your compile directory. + +Issue: + +mlir-opt --pass-pipeline="builtin.module(canonicalize, cse, loop-invariant-code-motion, canonicalize, cse, loop-invariant-code-motion,cse,canonicalize,fold-memref-alias-ops,lower-affine,finalize-memref-to-llvm{use-opaque-pointers=false},loop-invariant-code-motion,canonicalize,cse,convert-scf-to-openmp,finalize-memref-to-llvm{use-opaque-pointers=false},convert-scf-to-cf,convert-openmp-to-llvm,convert-math-to-llvm,convert-func-to-llvm,reconcile-unrealized-casts,canonicalize,cse)" stencil.mlir | mlir-translate --mlir-to-llvmir -o stencil.bc + +clang -g -c stencil.bc +flang-new -fc1 -emit-obj module_1.mlir +flang-new -fopenmp -o stencil stencil.o module_1.o + +And run the executable :) + +To compile, for MPI: + +./psy-opt -p apply-stencil-analysis,lower-psy-ir,lower-mpi,extract-stencil,rewrite-fir-to-standard psy_output.mlir + +Then copy the module 0 file out to the xdsl tools directory, and run + +./xdsl-opt -p apply-mpi,stencil-shape-inference,convert-stencil-to-ll-mlir,lower-mpi module_0.mlir -o stencil.mlir + +Then copy stencil.mlir and module_1.mlir (in generated directory) to your compile directory. + +Issue: + +mlir-opt --pass-pipeline="builtin.module(canonicalize, cse, loop-invariant-code-motion, canonicalize, cse, loop-invariant-code-motion,cse,canonicalize,fold-memref-alias-ops,lower-affine,finalize-memref-to-llvm{use-opaque-pointers=false},loop-invariant-code-motion,canonicalize,cse,convert-scf-to-openmp,finalize-memref-to-llvm{use-opaque-pointers=false},convert-scf-to-cf,convert-openmp-to-llvm,convert-math-to-llvm,convert-func-to-llvm,reconcile-unrealized-casts,canonicalize,cse)" stencil.mlir | mlir-translate --mlir-to-llvmir -o stencil.bc + +clang -g -c stencil.bc +flang-new -fc1 -emit-obj module_1.mlir +flang-new -o stencil stencil.o module_1.o -lmpi + +And run the executable using mpiexec :) + +To compile, for GPU: + +./psy-opt -p apply-stencil-analysis,lower-mpi,extract-stencil,rewrite-fir-to-standard psy_output.mlir + +Then copy the module 0 file out to the xdsl tools directory, and run + +./xdsl-opt -p stencil-shape-inference,convert-stencil-to-gpu module_0.mlir -o stencil-gpu.mlir + +Then copy stencil.mlir and module_1.mlir (in generated directory) to your compile directory. + +Issue (the mlir-opt needs to be on GPU node of Cirrus): + +(this pass pipeline is now incorrect) + +bin/mlir-opt --pass-pipeline="builtin.module(test-math-algebraic-simplification,scf-parallel-loop-tiling{parallel-loop-tile-sizes=1024,1,1}, canonicalize, func.func(gpu-map-parallel-loops), convert-parallel-loops-to-gpu, lower-affine, gpu-kernel-outlining,func.func(gpu-async-region),canonicalize,convert-arith-to-llvm{index-bitwidth=64},convert-memref-to-llvm{index-bitwidth=64},convert-scf-to-cf,convert-cf-to-llvm{index-bitwidth=64},gpu.module(convert-gpu-to-nvvm,reconcile-unrealized-casts,canonicalize,gpu-to-cubin),gpu-to-llvm,canonicalize)" stencil-gpu.mlir | bin/mlir-translate --mlir-to-llvmir -o stencil.bc + +clang -g -c stencil.bc +flang-new -fc1 -emit-obj module_1.mlir +flang-new -o stencil stencil.o module_1.o -lmpi + +And run the executable :) diff --git a/examples/xdsl/tra_adv/adv_reduced.F90 b/examples/xdsl/tra_adv/adv_reduced.F90 new file mode 100644 index 00000000000..d1a31c32395 --- /dev/null +++ b/examples/xdsl/tra_adv/adv_reduced.F90 @@ -0,0 +1,103 @@ + !!===================================================================================== + !! *** traadv kernel extracted from the NEMO software (http://www.nemo-ocean.eu ) *** + !! *** governed by the CeCILL licence (http://www.cecill.info) *** + !! + !! *** IS-ENES2 - CMCC/STFC *** + !!===================================================================================== +PROGRAM tra_adv + + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: mydomain, zwx, zwy, umask, vmask, zind + REAL*8, DIMENSION(:), ALLOCATABLE :: rnfmsk_z + REAL*8 :: zice, zu, z0u, zzwx, zv, z0v, zzwy, ztra, zbtr, zdt, zalpha + REAL*8 :: r, checksum + REAL*8 :: zw, z0w + INTEGER :: jpi, jpj, jpk, ji, jj, jk, jt + INTEGER*8 :: itn_count + integer :: itimer0, itimer1 + + + !jpi=256 + jpi=10 + !jpj=256 + jpj=20 + !jpk=256 + jpk=40 + itn_count=100 + + allocate(mydomain(jpi, jpj, jpk)) + allocate(zwx(jpi, jpj, jpk)) + allocate(zwy(jpi, jpj, jpk)) + allocate(umask(jpi, jpj, jpk)) + allocate(vmask(jpi, jpj, jpk)) + + !call timer_init() + !call timer_start(itimer0, label='Initialise') + +! arrays initialization + + r = jpi*jpj*jpk + + ! the following three lines can be uncommented to randomize arrays initialization + !call random_seed() + !call random_number(r) + r = r*jpi*jpj*jpk + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + umask(ji,jj,jk) = ji*jj*jk/r + mydomain(ji,jj,jk) =ji*jj*jk/r + vmask(ji,jj,jk)= ji*jj*jk/r + END DO + END DO + END DO + + !call timer_stop(itimer0) + !call timer_start(itimer1, label='Compute') + +!*********************** +!* Start of the symphony +!*********************** + + DO jt = 1, itn_count + + !DO jk = 1, jpk + ! DO jj = 1, jpj + ! DO ji = 1, jpi + ! zind(ji,jj,jk) = MAX ( & + ! rnfmsk(ji,jj) * rnfmsk_z(jk), & + ! upsmsk(ji,jj) & + ! & ) * tmask(ji,jj,jk) + ! zind(ji,jj,jk) = 1.0 - zind(ji,jj,jk) + ! END DO + ! END DO + ! END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jpk) = 0.e0 + zwy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 1, jpj-1 + DO ji = 1, jpi-1 + zwx(ji,jj,jk) = umask(ji,jj,jk) * ( mydomain(ji+1,jj,jk) - mydomain(ji,jj,jk) ) + zwy(ji,jj,jk) = vmask(ji,jj,jk) * ( mydomain(ji,jj+1,jk) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + END DO + + !call timer_stop(itimer1) + + !call timer_report() + + deallocate(mydomain) + deallocate(zwx) + deallocate(zwy) + deallocate(umask) + deallocate(vmask) +end program tra_adv diff --git a/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_heap.F90 b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_heap.F90 new file mode 100644 index 00000000000..ce2e9131859 --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_heap.F90 @@ -0,0 +1,83 @@ +subroutine main() + + use mpi + + real*8, dimension(:,:,:), allocatable :: su, sv, sw, u, v, w + real*8, dimension(:), allocatable :: tzc1, tzc2, tzd1, tzd2 + integer :: k, j, i, nx, ny, nz + integer :: itimer0, itimer1 + + nx=508 !512 + ny=512 !512 + nz=514 !512 + + allocate(su(nz, ny, nx)) + allocate(sv(nz, ny, nx)) + allocate(sw(nz, ny, nx)) + allocate(u(nz, ny, nx)) + allocate(v(nz, ny, nx)) + allocate(w(nz, ny, nx)) + allocate(tzc1(nz)) + allocate(tzc2(nz)) + allocate(tzd1(nz)) + allocate(tzd2(nz)) + + !call timer_init() + !call timer_start(itimer0, label='Initialise') + + do i=1, nx + do j=1, ny + do k=1, nz + u(k,j,i)=10.0 + v(k,j,i)=20.0 + w(k,j,i)=30.0 + end do + end do + end do + + do k=1, nz + tzc1(k)=50.0 + tzc2(k)=15.0 + tzd1(k)=100.0 + tzd2(k)=5.0 + end do + + !call timer_stop(itimer0) + !call timer_start(itimer1, label='Compute') + + do i=2,nx-1 + do j=2,ny-1 + do k=2,nz-1 + su(k, j, i)=& + (2.0*(u(k, j, i-1)*(u(k, j, i)+u(k, j, i-1))-u(k, j, i+1)*(u(k, j, i)+u(k, j, i+1)))) + & + (1.0*(u(k, j-1, i)*(v(k, j-1, i)+v(k, j-1, i+1))-u(k, j+1, i)*(v(k, j, i)+v(k, j, i+1)))) + & + (tzc1(k)*u(k-1, j, i)*(w(k-1, j, i)+w(k-1, j, i+1))-tzc2(k)*u(k+1, j, i)*(w(k, j, i)+w(k, j, i+1))) + + sv(k, j, i)=& + (2.0*(v(k, j-1, i)*(v(k, j, i)+v(k, j-1, i))-v(k, j+1, i)*(v(k, j, i)+v(k, j+1, i)))) + & + (2.0*(v(k, j, i-1)*(u(k, j, i-1)+u(k, j+1, i-1))-v(k, j, i+1)*(u(k, j, i)+u(k, j+1, i)))) + & + (tzc1(k)*v(k-1, j, i)*(w(k-1, j, i)+w(k-1, j+1, i))-tzc2(k)*v(k+1, j, i)*(w(k, j, i)+w(k, j+1, i))) + + sw(k, j, i)=& + (tzd1(k)*w(k-1, j, i)*(w(k, j, i)+w(k-1, j, i))-tzd2(k)*w(k+1, j, i)*(w(k, j, i)+w(k+1, j, i))) + & + (2.0*(w(k, j, i-1)*(u(k, j, i-1)+u(k+1, j, i-1))-w(k, j, i+1)*(u(k, j, i)+u(k+1, j, i)))) + & + (2.0*(w(k, j-1, i)*(v(k, j-1, i)+v(k+1, j-1, i))-w(k, j+1, i)*(v(k, j, i)+v(k+1, j, i)))) + end do + end do + end do + + !call timer_stop(itimer1) + + !call timer_report() + + deallocate(su) + deallocate(sv) + deallocate(sw) + deallocate(u) + deallocate(v) + deallocate(w) + deallocate(tzc1) + deallocate(tzc2) + deallocate(tzd1) + deallocate(tzd2) +end subroutine main diff --git a/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi.F90 b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi.F90 new file mode 100644 index 00000000000..de0fcce0518 --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi.F90 @@ -0,0 +1,182 @@ +subroutine main() + + !use mpi, only: MPI_Init, MPI_CommRank, MPI_Finalize + !use timer!, only: timer_init, timer_start, timer_stop, timer_report + + real*8, dimension(:,:,:), allocatable :: su, sv, sw, u, v, w + real*8, dimension(:), allocatable :: tzc1, tzc2, tzd1, tzd2 + integer :: k, j, i, nx, ny, nz, rank + integer :: itimer0, itimer1 + + !call MPI_Init() + + !rank=MPI_CommRank() + + ! Add space for the halos + !256 / 16 + 2 ; / 16 + 2 ; / 32 + 2 ; / 32 + 2 ; / 64 + 2 ; / 64 + 2 ; / 128 + 2 + !512 / 8 + 2 ; / 16 + 2 ; / 16 + 2 ; / 32 + 2 ; / 32 + 2 ; / 64 + 2 ; / 64 + 2 + !256 + + !nx=256 + !ny=512 + !nz=256 + + ! 1 node + !nx=18 + !ny=66 + !nz=258 + + ! 2 nodes + !nx=18 + !ny=34 + !nz=258 + + ! 4 nodes + !nx=10 + !ny=34 + !nz=258 + + ! 8 nodes + !nx=10 + !ny=18 + !nz=258 + + ! 16 nodes + !nx=6 + !ny=18 + !nz=258 + + ! 32 nodes + !nx=6 + !ny=10 + !nz=258 + + ! 64 nodes + !nx=4 + !ny=10 + !nz=258 + + ! 128 nodes + !nx=4 + !ny=6 + !nz=258 + + !! =================== Second run for ARCHER2 ============================ + ! 1 node + !nx=34 + !ny=66 + !nz=258 + + ! 2 nodes + !nx=34 + !ny=34 + !nz=258 + + ! 4 nodes + !nx=18 + !ny=34 + !nz=258 + + + ! 8 nodes + !nx=18 + !ny=18 + !nz=258 + + ! 16 nodes + !nx=10 + !ny=18 + !nz=258 + + ! 32 nodes + !nx=10 + !ny=10 + !nz=258 + + ! 64 nodes + !nx=6 + !ny=10 + !nz=258 + + ! 128 nodes + nx=6 + ny=6 + nz=258 + + allocate(su(nz, ny, nx)) + !allocate(sv(nz, ny, nx)) + !allocate(sw(nz, ny, nx)) + !allocate(u(nz, ny, nx)) + !allocate(v(nz, ny, nx)) + !allocate(w(nz, ny, nx)) + !allocate(tzc1(nz)) + !allocate(tzc2(nz)) + !allocate(tzd1(nz)) + !allocate(tzd2(nz)) + + !if (rank == 0) then + ! call timer_init() + ! call timer_start(itimer0, label='Initialise') + !end if + + !do i=1, nx + ! do j=1, ny + ! do k=1, nz + ! u(k,j,i)=10.0 + ! v(k,j,i)=20.0 + ! w(k,j,i)=30.0 + ! end do + ! end do + !end do + + !do k=1, nz + ! tzc1(k)=50.0 + ! tzc2(k)=15.0 + ! tzd1(k)=100.0 + ! tzd2(k)=5.0 + !end do + + !if (rank == 0) then + ! call timer_stop(itimer0) + ! call timer_start(itimer1, label='Compute') + !end if + + !do i=2,nx-1 + ! do j=2,ny-1 + ! do k=2,nz-1 + ! su(k, j, i)=& + ! (2.0*(u(k, j, i-1)*(u(k, j, i)+u(k, j, i-1))-u(k, j, i+1)*(u(k, j, i)+u(k, j, i+1)))) + & + ! (1.0*(u(k, j-1, i)*(v(k, j-1, i)+v(k, j-1, i+1))-u(k, j+1, i)*(v(k, j, i)+v(k, j, i+1)))) + & + ! (tzc1(k)*u(k-1, j, i)*(w(k-1, j, i)+w(k-1, j, i+1))-tzc2(k)*u(k+1, j, i)*(w(k, j, i)+w(k, j, i+1))) + + ! sv(k, j, i)=& + ! (2.0*(v(k, j-1, i)*(v(k, j, i)+v(k, j-1, i))-v(k, j+1, i)*(v(k, j, i)+v(k, j+1, i)))) + & + ! (2.0*(v(k, j, i-1)*(u(k, j, i-1)+u(k, j+1, i-1))-v(k, j, i+1)*(u(k, j, i)+u(k, j+1, i)))) + & + ! (tzc1(k)*v(k-1, j, i)*(w(k-1, j, i)+w(k-1, j+1, i))-tzc2(k)*v(k+1, j, i)*(w(k, j, i)+w(k, j+1, i))) + + ! sw(k, j, i)=& + ! (tzd1(k)*w(k-1, j, i)*(w(k, j, i)+w(k-1, j, i))-tzd2(k)*w(k+1, j, i)*(w(k, j, i)+w(k+1, j, i))) + & + ! (2.0*(w(k, j, i-1)*(u(k, j, i-1)+u(k+1, j, i-1))-w(k, j, i+1)*(u(k, j, i)+u(k+1, j, i)))) + & + ! (2.0*(w(k, j-1, i)*(v(k, j-1, i)+v(k+1, j-1, i))-w(k, j+1, i)*(v(k, j, i)+v(k+1, j, i)))) + ! end do + ! end do + !end do + + !if (rank == 0) then + ! call timer_stop(itimer1) + ! call timer_report() + !end if + + !deallocate(su) + !deallocate(sv) + !deallocate(sw) + !deallocate(u) + !deallocate(v) + !deallocate(w) + !deallocate(tzc1) + !deallocate(tzc2) + !deallocate(tzd1) + !deallocate(tzd2) + + !call MPI_Finalize() +end subroutine main diff --git a/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi_orig.F90 b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi_orig.F90 new file mode 100644 index 00000000000..b9d43b2547e --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_mpi_orig.F90 @@ -0,0 +1,137 @@ +subroutine main() + real*8, dimension(:,:,:), allocatable :: su, sv, sw, u, v, w + real*8, dimension(:), allocatable :: tzc1, tzc2, tzd1, tzd2 + integer :: k, j, i, nx, ny, nz, rank + integer :: itimer0, itimer1 + + call MPI_Init() + + rank=MPI_CommRank() + + !nx=256 + !ny=512 + !nz=256 + + ! Add space for the halos + !256 / 16 + 2 ; / 16 + 2 ; / 32 + 2 ; / 32 + 2 ; / 64 + 2 ; / 64 + 2 ; / 128 + 2 + !512 / 8 + 2 ; / 16 + 2 ; / 16 + 2 ; / 32 + 2 ; / 32 + 2 ; / 64 + 2 ; / 64 + 2 + !256 + + ! 1 node + nx=18 + ny=66 + nz=258 + + ! 2 nodes + !nx=18 + !ny=34 + !nz=258 + + ! 4 nodes + !nx=10 + !ny=34 + !nz=258 + + ! 8 nodes + !nx=10 + !ny=18 + !nz=258 + + ! 16 nodes + !nx=6 + !ny=18 + !nz=258 + + ! 32 nodes + !nx=6 + !ny=10 + !nz=258 + + ! 64 nodes + !nx=4 + !ny=10 + !nz=258 + + ! 128 nodes + !nx=4 + !ny=6 + !nz=258 + + + allocate(su(nz, ny, nx)) + allocate(sv(nz, ny, nx)) + allocate(sw(nz, ny, nx)) + allocate(u(nz, ny, nx)) + allocate(v(nz, ny, nx)) + allocate(w(nz, ny, nx)) + allocate(tzc1(nz)) + allocate(tzc2(nz)) + allocate(tzd1(nz)) + allocate(tzd2(nz)) + + if (rank == 0) then + call timer_init() + call timer_start(itimer0, label='Initialise') + end if + + do i=1, nx + do j=1, ny + do k=1, nz + u(k,j,i)=10.0 + v(k,j,i)=20.0 + w(k,j,i)=30.0 + end do + end do + end do + + do k=1, nz + tzc1(k)=50.0 + tzc2(k)=15.0 + tzd1(k)=100.0 + tzd2(k)=5.0 + end do + + if (rank == 0) then + call timer_stop(itimer0) + call timer_start(itimer1, label='Compute') + end if + + do i=2,nx-1 + do j=2,ny-1 + do k=2,nz-1 + su(k, j, i)=& + (2.0*(u(k, j, i-1)*(u(k, j, i)+u(k, j, i-1))-u(k, j, i+1)*(u(k, j, i)+u(k, j, i+1)))) + & + (1.0*(u(k, j-1, i)*(v(k, j-1, i)+v(k, j-1, i+1))-u(k, j+1, i)*(v(k, j, i)+v(k, j, i+1)))) + & + (tzc1(k)*u(k-1, j, i)*(w(k-1, j, i)+w(k-1, j, i+1))-tzc2(k)*u(k+1, j, i)*(w(k, j, i)+w(k, j, i+1))) + + sv(k, j, i)=& + (2.0*(v(k, j-1, i)*(v(k, j, i)+v(k, j-1, i))-v(k, j+1, i)*(v(k, j, i)+v(k, j+1, i)))) + & + (2.0*(v(k, j, i-1)*(u(k, j, i-1)+u(k, j+1, i-1))-v(k, j, i+1)*(u(k, j, i)+u(k, j+1, i)))) + & + (tzc1(k)*v(k-1, j, i)*(w(k-1, j, i)+w(k-1, j+1, i))-tzc2(k)*v(k+1, j, i)*(w(k, j, i)+w(k, j+1, i))) + + sw(k, j, i)=& + (tzd1(k)*w(k-1, j, i)*(w(k, j, i)+w(k-1, j, i))-tzd2(k)*w(k+1, j, i)*(w(k, j, i)+w(k+1, j, i))) + & + (2.0*(w(k, j, i-1)*(u(k, j, i-1)+u(k+1, j, i-1))-w(k, j, i+1)*(u(k, j, i)+u(k+1, j, i)))) + & + (2.0*(w(k, j-1, i)*(v(k, j-1, i)+v(k+1, j-1, i))-w(k, j+1, i)*(v(k, j, i)+v(k+1, j, i)))) + end do + end do + end do + + if (rank == 0) then + call timer_stop(itimer1) + call timer_report() + end if + + deallocate(su) + deallocate(sv) + deallocate(sw) + deallocate(u) + deallocate(v) + deallocate(w) + deallocate(tzc1) + deallocate(tzc2) + deallocate(tzd1) + deallocate(tzd2) + + call MPI_Finalize() +end subroutine main \ No newline at end of file diff --git a/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_stack.F90 b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_stack.F90 new file mode 100644 index 00000000000..eeda609ee1f --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/pw_advection/advection_stack.F90 @@ -0,0 +1,59 @@ +subroutine main() + real*8, dimension(1024,1024,1024) :: su, sv, sw, u, v, w + real*8, dimension(1024) :: tzc1, tzc2, tzd1, tzd2 + integer :: k, j, i, nx, ny, nz + integer :: itimer0, itimer1 + + nx=1024 + ny=1024 + nz=1024 + + call timer_init() + call timer_start(itimer0, label='Initialise') + + do i=1, nx + do j=1, ny + do k=1, nz + u(k,j,i)=10.0 + v(k,j,i)=20.0 + w(k,j,i)=30.0 + end do + end do + end do + + do k=1, nz + tzc1(k)=50.0 + tzc2(k)=15.0 + tzd1(k)=100.0 + tzd2(k)=5.0 + end do + + call timer_stop(itimer0) + call timer_start(itimer1, label='Compute') + + + do i=2,nx-1 + do j=2,ny-1 + do k=2,nz-1 + su(k, j, i)=& + (2.0*(u(k, j, i-1)*(u(k, j, i)+u(k, j, i-1))-u(k, j, i+1)*(u(k, j, i)+u(k, j, i+1)))) + & + (1.0*(u(k, j-1, i)*(v(k, j-1, i)+v(k, j-1, i+1))-u(k, j+1, i)*(v(k, j, i)+v(k, j, i+1)))) + & + (tzc1(k)*u(k-1, j, i)*(w(k-1, j, i)+w(k-1, j, i+1))-tzc2(k)*u(k+1, j, i)*(w(k, j, i)+w(k, j, i+1))) + + sv(k, j, i)=& + (2.0*(v(k, j-1, i)*(v(k, j, i)+v(k, j-1, i))-v(k, j+1, i)*(v(k, j, i)+v(k, j+1, i)))) + & + (2.0*(v(k, j, i-1)*(u(k, j, i-1)+u(k, j+1, i-1))-v(k, j, i+1)*(u(k, j, i)+u(k, j+1, i)))) + & + (tzc1(k)*v(k-1, j, i)*(w(k-1, j, i)+w(k-1, j+1, i))-tzc2(k)*v(k+1, j, i)*(w(k, j, i)+w(k, j+1, i))) + + sw(k, j, i)=& + (tzd1(k)*w(k-1, j, i)*(w(k, j, i)+w(k-1, j, i))-tzd2(k)*w(k+1, j, i)*(w(k, j, i)+w(k+1, j, i))) + & + (2.0*(w(k, j, i-1)*(u(k, j, i-1)+u(k+1, j, i-1))-w(k, j, i+1)*(u(k, j, i)+u(k+1, j, i)))) + & + (2.0*(w(k, j-1, i)*(v(k, j-1, i)+v(k+1, j-1, i))-w(k, j+1, i)*(v(k, j, i)+v(k+1, j, i)))) + end do + end do + end do + + call timer_stop(itimer1) + + call timer_report() +end subroutine main diff --git a/examples/xdsl/tra_adv/benchmarks/tra_adv/simple.F90 b/examples/xdsl/tra_adv/benchmarks/tra_adv/simple.F90 new file mode 100644 index 00000000000..819342bfca7 --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/tra_adv/simple.F90 @@ -0,0 +1,8 @@ +program print_value + implicit none + integer :: age + + age = 42 + print *, "Your age is: ", age + +end program print_value diff --git a/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_heap.F90 b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_heap.F90 new file mode 100644 index 00000000000..b899736ddc6 --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_heap.F90 @@ -0,0 +1,263 @@ + !!===================================================================================== + !! *** traadv kernel extracted from the NEMO software (http://www.nemo-ocean.eu ) *** + !! *** governed by the CeCILL licence (http://www.cecill.info) *** + !! + !! *** IS-ENES2 - CMCC/STFC *** + !!===================================================================================== +PROGRAM tra_adv + + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: tsn + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: pun, pvn, pwn + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: mydomain, zslpx, zslpy, zwx, zwy, umask, vmask, tmask, zind + REAL*8, DIMENSION(:,:), ALLOCATABLE :: ztfreez, rnfmsk, upsmsk + REAL*8, DIMENSION(:), ALLOCATABLE :: rnfmsk_z + REAL*8 :: zice, zu, z0u, zzwx, zv, z0v, zzwy, ztra, zbtr, zdt, zalpha + REAL*8 :: r, checksum + REAL*8 :: zw, z0w + INTEGER :: jpi, jpj, jpk, ji, jj, jk, jt + INTEGER*8 :: itn_count + integer :: itimer0, itimer1 + + + jpi=512 + jpj=512 + jpk=512 + itn_count=100 + + allocate(tsn(jpi, jpj, jpk)) + allocate(pun(jpi, jpj, jpk)) + allocate(pvn(jpi, jpj, jpk)) + allocate(pwn(jpi, jpj, jpk)) + + allocate(mydomain(jpi, jpj, jpk)) + allocate(zslpx(jpi, jpj, jpk)) + allocate(zslpy(jpi, jpj, jpk)) + allocate(zwx(jpi, jpj, jpk)) + allocate(zwy(jpi, jpj, jpk)) + allocate(umask(jpi, jpj, jpk)) + allocate(vmask(jpi, jpj, jpk)) + allocate(tmask(jpi, jpj, jpk)) + allocate(zind(jpi, jpj, jpk)) + + allocate(ztfreez(jpi, jpj)) + allocate(rnfmsk(jpi, jpj)) + allocate(upsmsk(jpi, jpj)) + allocate(rnfmsk_z(jpk)) + + call timer_init() + call timer_start(itimer0, label='Initialise') + +! arrays initialization + + r = jpi*jpj*jpk + + ! the following three lines can be uncommented to randomize arrays initialization + !call random_seed() + !call random_number(r) + !r = r*jpi*jpj*jpk + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + umask(ji,jj,jk) = ji*jj*jk/r + mydomain(ji,jj,jk) =ji*jj*jk/r + pun(ji,jj,jk) =ji*jj*jk/r + pvn(ji,jj,jk) =ji*jj*jk/r + pwn(ji,jj,jk) =ji*jj*jk/r + vmask(ji,jj,jk)= ji*jj*jk/r + tsn(ji,jj,jk)= ji*jj*jk/r + tmask(ji,jj,jk)= ji*jj*jk/r + END DO + END DO + END DO + + r = jpi*jpj + DO jj=1, jpj + DO ji=1, jpi + ztfreez(ji,jj) = ji*jj/r + upsmsk(ji,jj) = ji*jj/r + rnfmsk(ji,jj) = ji*jj/r + END DO + END DO + + DO jk=1, jpk + rnfmsk_z(jk)=jk/jpk + END DO + + call timer_stop(itimer0) + call timer_start(itimer1, label='Compute') + +!*********************** +!* Start of the symphony +!*********************** + + DO jt = 1, itn_count + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + zind(ji,jj,jk) = MAX ( & + rnfmsk(ji,jj) * rnfmsk_z(jk), & + upsmsk(ji,jj) & + & ) * tmask(ji,jj,jk) + zind(ji,jj,jk) = 1.0 - zind(ji,jj,jk) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jpk) = 0.e0 + zwy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 1, jpj-1 + DO ji = 1, jpi-1 + zwx(ji,jj,jk) = umask(ji,jj,jk) * ( mydomain(ji+1,jj,jk) - mydomain(ji,jj,jk) ) + zwy(ji,jj,jk) = vmask(ji,jj,jk) * ( mydomain(ji,jj+1,jk) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jpk) = 0.e0 + zslpy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji-1,jj ,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji-1,jj ,jk) ) ) + zslpy(ji,jj,jk) = ( zwy(ji,jj,jk) + zwy(ji ,jj-1,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwy(ji,jj,jk) * zwy(ji ,jj-1,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji ,jj,jk) ), & + & 2.d0*ABS( zwx (ji-1,jj,jk) ), & + & 2.d0*ABS( zwx (ji ,jj,jk) ) ) + zslpy(ji,jj,jk) = SIGN( 1.d0, zslpy(ji,jj,jk) ) * MIN( ABS( zslpy(ji,jj ,jk) ), & + & 2.d0*ABS( zwy (ji,jj-1,jk) ), & + & 2.d0*ABS( zwy (ji,jj ,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk) = pun(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) )) * mydomain(ji+1,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji+1,jj,jk)) + (1.-(0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) ))) * mydomain(ji ,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji ,jj,jk)) ) + + + zwy(ji,jj,jk) = pvn(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) )) * mydomain(ji,jj+1,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj+1,jk)) + (1.d0-(0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) ))) * mydomain(ji,jj ,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj ,jk)) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = mydomain(ji,jj,jk) + (- 1. * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) & + & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) )) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx (ji,jj, 1 ) = 0.e0 + zwx (ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jk) = tmask(ji,jj,jk) * ( mydomain(ji,jj,jk-1) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,1) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji,jj,jk+1) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji,jj,jk+1) ) ) + END DO + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji,jj,jk ) ), & + & 2.d0*ABS( zwx (ji,jj,jk+1) ), & + & 2.d0*ABS( zwx (ji,jj,jk ) ) ) + END DO + END DO + END DO + + DO jk = 1, 1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj, jk) = pwn(ji,jj,jk) * mydomain(ji,jj,jk) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk+1) = pwn(ji,jj,jk+1) * ( 0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) ) * (mydomain(ji,jj,jk+1) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk+1))) + (1.-0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) )) * (mydomain(ji,jj,jk ) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk ))) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = - 1.0 * ( zwx(ji,jj,jk) - zwx(ji,jj,jk+1) ) + END DO + END DO + END DO + END DO + + call timer_stop(itimer1) + + call timer_report() + + deallocate(tsn) + deallocate(pun) + deallocate(pvn) + deallocate(pwn) + + deallocate(mydomain) + deallocate(zslpx) + deallocate(zslpy) + deallocate(zwx) + deallocate(zwy) + deallocate(umask) + deallocate(vmask) + deallocate(tmask) + deallocate(zind) + + deallocate(ztfreez) + deallocate(rnfmsk) + deallocate(upsmsk) + deallocate(rnfmsk_z) +end program tra_adv diff --git a/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_mpi.F90 b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_mpi.F90 new file mode 100644 index 00000000000..c4ecf0a58ec --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_mpi.F90 @@ -0,0 +1,280 @@ + !!===================================================================================== + !! *** traadv kernel extracted from the NEMO software (http://www.nemo-ocean.eu ) *** + !! *** governed by the CeCILL licence (http://www.cecill.info) *** + !! + !! *** IS-ENES2 - CMCC/STFC *** + !!===================================================================================== +PROGRAM tra_adv + + use mpi + + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: tsn + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: pun, pvn, pwn + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: mydomain, zslpx, zslpy, zwx, zwy, umask, vmask, tmask, zind + !REAL*8, DIMENSION(:,:), ALLOCATABLE :: ztfreez, rnfmsk, upsmsk + !REAL*8, DIMENSION(:), ALLOCATABLE :: rnfmsk_z + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: ztfreez, rnfmsk, upsmsk + REAL*8, DIMENSION(:,:,:), ALLOCATABLE :: rnfmsk_z + REAL*8 :: zice, zu, z0u, zzwx, zv, z0v, zzwy, ztra, zbtr, zdt, zalpha + REAL*8 :: r, checksum + REAL*8 :: zw, z0w + INTEGER :: jpi, jpj, jpk, ji, jj, jk, jt + INTEGER*8 :: itn_count + integer :: itimer0, itimer1, fixed + + call MPI_Init() + + jpi=128 !130 + jpj=32 !130 + jpk=16 !130 + !jpi=256 + !jpj=256 + !jpk=256 + itn_count=100 + fixed = 1 + + allocate(tsn(jpi, jpj, jpk)) + allocate(pun(jpi, jpj, jpk)) + allocate(pvn(jpi, jpj, jpk)) + allocate(pwn(jpi, jpj, jpk)) + + allocate(mydomain(jpi, jpj, jpk)) + allocate(zslpx(jpi, jpj, jpk)) + allocate(zslpy(jpi, jpj, jpk)) + allocate(zwx(jpi, jpj, jpk)) + allocate(zwy(jpi, jpj, jpk)) + allocate(umask(jpi, jpj, jpk)) + allocate(vmask(jpi, jpj, jpk)) + allocate(tmask(jpi, jpj, jpk)) + allocate(zind(jpi, jpj, jpk)) + +! allocate(ztfreez(jpi, jpj)) +! allocate(rnfmsk(jpi, jpj)) +! allocate(upsmsk(jpi, jpj)) +! allocate(rnfmsk_z(jpk)) + + allocate(ztfreez(1, jpi, jpj)) + allocate(rnfmsk(1, jpi, jpj)) + allocate(upsmsk(1, jpi, jpj)) + allocate(rnfmsk_z(1, 1, jpk)) + + + call timer_init() + call timer_start(itimer0, label='Initialise') + +! arrays initialization + + r = jpi*jpj*jpk + + ! the following three lines can be uncommented to randomize arrays initialization + !call random_seed() + !call random_number(r) + !r = r*jpi*jpj*jpk + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + umask(ji,jj,jk) = ji*jj*jk/r + mydomain(ji,jj,jk) =ji*jj*jk/r + pun(ji,jj,jk) =ji*jj*jk/r + pvn(ji,jj,jk) =ji*jj*jk/r + pwn(ji,jj,jk) =ji*jj*jk/r + vmask(ji,jj,jk)= ji*jj*jk/r + tsn(ji,jj,jk)= ji*jj*jk/r + tmask(ji,jj,jk)= ji*jj*jk/r + END DO + END DO + END DO + + r = jpi*jpj + DO jj=1, jpj + DO ji=1, jpi + ztfreez(fixed,ji,jj) = ji*jj/r + upsmsk(fixed,ji,jj) = ji*jj/r + rnfmsk(fixed,ji,jj) = ji*jj/r + END DO + END DO + + DO jk=1, jpk + rnfmsk_z(fixed,fixed,jk)=jk/jpk + END DO + +!*********************** +!* Start of the symphony +!*********************** + + call timer_stop(itimer0) + call timer_start(itimer1, label='Compute') + + DO jt = 1, itn_count + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + zind(ji,jj,jk) = MAX ( & + rnfmsk(fixed,ji,jj) * rnfmsk_z(1,1,jk), & + upsmsk(fixed,ji,jj) & + & ) * tmask(ji,jj,jk) + zind(ji,jj,jk) = 1.0 - zind(ji,jj,jk) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jpk) = 0.e0 + zwy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 1, jpj-1 + DO ji = 1, jpi-1 + zwx(ji,jj,jk) = umask(ji,jj,jk) * ( mydomain(ji+1,jj,jk) - mydomain(ji,jj,jk) ) + zwy(ji,jj,jk) = vmask(ji,jj,jk) * ( mydomain(ji,jj+1,jk) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jpk) = 0.e0 + zslpy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji-1,jj ,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji-1,jj ,jk) ) ) + zslpy(ji,jj,jk) = ( zwy(ji,jj,jk) + zwy(ji ,jj-1,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwy(ji,jj,jk) * zwy(ji ,jj-1,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji ,jj,jk) ), & + & 2.d0*ABS( zwx (ji-1,jj,jk) ), & + & 2.d0*ABS( zwx (ji ,jj,jk) ) ) + zslpy(ji,jj,jk) = SIGN( 1.d0, zslpy(ji,jj,jk) ) * MIN( ABS( zslpy(ji,jj ,jk) ), & + & 2.d0*ABS( zwy (ji,jj-1,jk) ), & + & 2.d0*ABS( zwy (ji,jj ,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk) = pun(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) )) * mydomain(ji+1,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji+1,jj,jk)) + (1.-(0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) ))) * mydomain(ji ,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji ,jj,jk)) ) + + + zwy(ji,jj,jk) = pvn(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) )) * mydomain(ji,jj+1,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj+1,jk)) + (1.d0-(0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) ))) * mydomain(ji,jj ,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj ,jk)) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = mydomain(ji,jj,jk) + (- 1. * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) & + & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) )) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx (ji,jj, 1 ) = 0.e0 + zwx (ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jk) = tmask(ji,jj,jk) * ( mydomain(ji,jj,jk-1) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,1) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji,jj,jk+1) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji,jj,jk+1) ) ) + END DO + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji,jj,jk ) ), & + & 2.d0*ABS( zwx (ji,jj,jk+1) ), & + & 2.d0*ABS( zwx (ji,jj,jk ) ) ) + END DO + END DO + END DO + + DO jk = 1, 1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj, jk) = pwn(ji,jj,jk) * mydomain(ji,jj,jk) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk+1) = pwn(ji,jj,jk+1) * ( 0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) ) * (mydomain(ji,jj,jk+1) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk+1))) + (1.-0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) )) * (mydomain(ji,jj,jk ) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk ))) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = - 1.0 * ( zwx(ji,jj,jk) - zwx(ji,jj,jk+1) ) + END DO + END DO + END DO + END DO + + call timer_stop(itimer1) + + call timer_report() + + deallocate(tsn) + deallocate(pun) + deallocate(pvn) + deallocate(pwn) + + deallocate(mydomain) + deallocate(zslpx) + deallocate(zslpy) + deallocate(zwx) + deallocate(zwy) + deallocate(umask) + deallocate(vmask) + deallocate(tmask) + deallocate(zind) + + deallocate(ztfreez) + deallocate(rnfmsk) + deallocate(upsmsk) + deallocate(rnfmsk_z) + + call MPI_Finalize() +end program tra_adv diff --git a/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_stack.F90 b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_stack.F90 new file mode 100644 index 00000000000..5c697d1bb06 --- /dev/null +++ b/examples/xdsl/tra_adv/benchmarks/tra_adv/tra_adv_stack.F90 @@ -0,0 +1,216 @@ + !!===================================================================================== + !! *** traadv kernel extracted from the NEMO software (http://www.nemo-ocean.eu ) *** + !! *** governed by the CeCILL licence (http://www.cecill.info) *** + !! + !! *** IS-ENES2 - CMCC/STFC *** + !!===================================================================================== +PROGRAM tra_adv + + REAL*8, DIMENSION(64,64,64) :: tsn + REAL*8, DIMENSION(64,64,64) :: pun, pvn, pwn + REAL*8, DIMENSION(64,64,64) :: mydomain, zslpx, zslpy, zwx, zwy, umask, vmask, tmask, zind + REAL*8, DIMENSION(64,64) :: ztfreez, rnfmsk, upsmsk + REAL*8, DIMENSION(64) :: rnfmsk_z + REAL*8 :: zice, zu, z0u, zzwx, zv, z0v, zzwy, ztra, zbtr, zdt, zalpha + REAL*8 :: r, checksum + REAL*8 :: zw, z0w + INTEGER :: jpi, jpj, jpk, ji, jj, jk, jt + INTEGER*8 :: itn_count + + + jpi=64 + jpj=64 + jpk=64 + itn_count=1000 + + + +! arrays initialization + + r = jpi*jpj*jpk + + ! the following three lines can be uncommented to randomize arrays initialization + !call random_seed() + !call random_number(r) + !r = r*jpi*jpj*jpk + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + umask(ji,jj,jk) = ji*jj*jk/r + mydomain(ji,jj,jk) =ji*jj*jk/r + pun(ji,jj,jk) =ji*jj*jk/r + pvn(ji,jj,jk) =ji*jj*jk/r + pwn(ji,jj,jk) =ji*jj*jk/r + vmask(ji,jj,jk)= ji*jj*jk/r + tsn(ji,jj,jk)= ji*jj*jk/r + tmask(ji,jj,jk)= ji*jj*jk/r + END DO + END DO + END DO + + r = jpi*jpj + DO jj=1, jpj + DO ji=1, jpi + ztfreez(ji,jj) = ji*jj/r + upsmsk(ji,jj) = ji*jj/r + rnfmsk(ji,jj) = ji*jj/r + END DO + END DO + + DO jk=1, jpk + rnfmsk_z(jk)=jk/jpk + END DO + +!*********************** +!* Start of the symphony +!*********************** + + DO jt = 1, itn_count + + DO jk = 1, jpk + DO jj = 1, jpj + DO ji = 1, jpi + zind(ji,jj,jk) = MAX ( & + rnfmsk(ji,jj) * rnfmsk_z(jk), & + upsmsk(ji,jj) & + & ) * tmask(ji,jj,jk) + zind(ji,jj,jk) = 1.0 - zind(ji,jj,jk) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jpk) = 0.e0 + zwy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 1, jpj-1 + DO ji = 1, jpi-1 + zwx(ji,jj,jk) = umask(ji,jj,jk) * ( mydomain(ji+1,jj,jk) - mydomain(ji,jj,jk) ) + zwy(ji,jj,jk) = vmask(ji,jj,jk) * ( mydomain(ji,jj+1,jk) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jpk) = 0.e0 + zslpy(ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji-1,jj ,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji-1,jj ,jk) ) ) + zslpy(ji,jj,jk) = ( zwy(ji,jj,jk) + zwy(ji ,jj-1,jk) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwy(ji,jj,jk) * zwy(ji ,jj-1,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj + DO ji = 2, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji ,jj,jk) ), & + & 2.d0*ABS( zwx (ji-1,jj,jk) ), & + & 2.d0*ABS( zwx (ji ,jj,jk) ) ) + zslpy(ji,jj,jk) = SIGN( 1.d0, zslpy(ji,jj,jk) ) * MIN( ABS( zslpy(ji,jj ,jk) ), & + & 2.d0*ABS( zwy (ji,jj-1,jk) ), & + & 2.d0*ABS( zwy (ji,jj ,jk) ) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk) = pun(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) )) * mydomain(ji+1,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji+1,jj,jk)) + (1.-(0.5d0 - SIGN( 0.5d0, pun(ji,jj,jk) ))) * mydomain(ji ,jj,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pun(ji,jj,jk) ) - 0.5d0 * pun(ji,jj,jk) * 1.) * zslpx(ji ,jj,jk)) ) + + + zwy(ji,jj,jk) = pvn(ji,jj,jk) * ( (0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) )) * mydomain(ji,jj+1,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj+1,jk)) + (1.d0-(0.5d0 - SIGN( 0.5d0, pvn(ji,jj,jk) ))) * mydomain(ji,jj ,jk) + zind(ji,jj,jk) * ((SIGN( 0.5d0, pvn(ji,jj,jk) ) - 0.5d0 * pvn(ji,jj,jk) * 1.) * zslpy(ji,jj ,jk)) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = mydomain(ji,jj,jk) + (- 1. * ( zwx(ji,jj,jk) - zwx(ji-1,jj ,jk ) & + & + zwy(ji,jj,jk) - zwy(ji ,jj-1,jk ) )) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zwx (ji,jj, 1 ) = 0.e0 + zwx (ji,jj,jpk) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj,jk) = tmask(ji,jj,jk) * ( mydomain(ji,jj,jk-1) - mydomain(ji,jj,jk) ) + END DO + END DO + END DO + + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,1) = 0.e0 + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = ( zwx(ji,jj,jk) + zwx(ji,jj,jk+1) ) & + & * ( 0.25d0 + SIGN( 0.25d0, zwx(ji,jj,jk) * zwx(ji,jj,jk+1) ) ) + END DO + END DO + END DO + + DO jk = 2, jpk-1 + DO jj = 1, jpj + DO ji = 1, jpi + zslpx(ji,jj,jk) = SIGN( 1.d0, zslpx(ji,jj,jk) ) * MIN( ABS( zslpx(ji,jj,jk ) ), & + & 2.d0*ABS( zwx (ji,jj,jk+1) ), & + & 2.d0*ABS( zwx (ji,jj,jk ) ) ) + END DO + END DO + END DO + + DO jk = 1, 1 + DO jj = 1, jpj + DO ji = 1, jpi + zwx(ji,jj, jk) = pwn(ji,jj,jk) * mydomain(ji,jj,jk) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + zwx(ji,jj,jk+1) = pwn(ji,jj,jk+1) * ( 0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) ) * (mydomain(ji,jj,jk+1) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk+1))) + (1.-0.5d0 + SIGN( 0.5d0, pwn(ji,jj,jk+1) )) * (mydomain(ji,jj,jk ) + zind(ji,jj,jk) * (SIGN( 0.5d0, pwn(ji,jj,jk+1) ) - 0.5d0 * pwn(ji,jj,jk+1) * 1.0 * 1.0 * zslpx(ji,jj,jk ))) ) + END DO + END DO + END DO + + DO jk = 1, jpk-1 + DO jj = 2, jpj-1 + DO ji = 2, jpi-1 + mydomain(ji,jj,jk) = - 1.0 * ( zwx(ji,jj,jk) - zwx(ji,jj,jk+1) ) + END DO + END DO + END DO + END DO + + +end program tra_adv diff --git a/examples/xdsl/tra_adv/code_sample/array_test.F90 b/examples/xdsl/tra_adv/code_sample/array_test.F90 new file mode 100644 index 00000000000..73acc4f32e5 --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/array_test.F90 @@ -0,0 +1,42 @@ + +module my_module +contains + + + subroutine main() + integer :: a, b, i, j, k + + integer :: data_1(10,10,10) + integer, dimension(:,:,:), allocatable :: alloc_data + + allocate(alloc_data(10,10,10)) + + do i=1, 10 + do j=1, 10 + do k=1, 10 + data_1(k,j,i)=(i*10*10)+(j*10)+k + alloc_data(k,j,i)=(i*10*10)+(j*10)+k + end do + end do + end do + + do i=1, 10 + do j=1, 10 + do k=1, 10 + a=data_1(k,j,i) + print *, j, i, k, a + end do + end do + end do + end subroutine main +end module my_module + + + +!program mpi_test +!use mpi_tester +!implicit none + +! call test() + +!end program mpi_test \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/gauss_seidel.F90 b/examples/xdsl/tra_adv/code_sample/gauss_seidel.F90 new file mode 100644 index 00000000000..fdac8f67213 --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/gauss_seidel.F90 @@ -0,0 +1,32 @@ +subroutine main() + real :: data(256, 256) + real :: data2(256) + real :: data3(256, 256, 256) + integer :: i, j, k + + call MPI_Init() + + !do i = 2, 255, 1 + ! data2(i) = 1.0 + !enddo + + do k = 1, 1000, 1 + do i = 2, 255, 1 + do j = 2, 255, 1 + data(j,i) = (data(j,i - 1) + data(j,i + 1) + data(j - 1,i) + data(j + 1,i)) * 0.25 + enddo + enddo + enddo + + !do k = 1, 255, 1 + ! do i = 2, 255, 1 + ! do j = 2, 255, 1 + ! data3(j,i,k) = data3(j,i-1,k) + data3(j,i + 1,k) ! + data(j,i+1) + ! enddo + ! enddo + !enddo + + + call MPI_Finalize() + +end subroutine main \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/mpi_test.F90 b/examples/xdsl/tra_adv/code_sample/mpi_test.F90 new file mode 100644 index 00000000000..3e30ab5acb0 --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/mpi_test.F90 @@ -0,0 +1,67 @@ + +module my_module +contains + + subroutine init_data(d) + real, intent(inout) :: d(64,64) + + integer :: i, j + + do i=2, 63 + do j=1, 64 + d(j, i)=0.0 + end do + end do + do j=1, 64 + d(j, 1)=1.0 + d(j, 64)=10.0 + end do + end subroutine init_data + + + subroutine main() + integer :: rank, i,j, it + + real :: dd(64,64), v, bnorm, rnorm, norm + + call init_data(dd) + + bnorm=0.0 + + do i=2, 63 + do j=2, 63 + bnorm=bnorm+((dd(j,i)*4-dd(j-1,i)-dd(j+1,i)-dd(j,i-1)-dd(j,i+1)) ** 2) + end do + end do + + bnorm=sqrt(bnorm) + + do it=1, 1000 + rnorm=0.0 + do i=2, 63 + do j=2, 63 + rnorm=rnorm+((dd(j,i)*4-dd(j-1,i)-dd(j+1,i)-dd(j,i-1)-dd(j,i+1)) ** 2) + end do + end do + norm=sqrt(rnorm)/bnorm + print *, "Iteration: ", it, " norm of ", norm + + do i=2, 63 + do j=2, 63 + dd(j,i)=0.25*(dd(j-1,i) + dd(j+1,i) + dd(j,i-1) + dd(j,i+1)) + end do + end do + end do + end subroutine main + +end module my_module + + + +!program mpi_test +!use mpi_tester +!implicit none + +! call test() + +!end program mpi_test \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/mpi_test3.F90 b/examples/xdsl/tra_adv/code_sample/mpi_test3.F90 new file mode 100644 index 00000000000..1f0b86a1f12 --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/mpi_test3.F90 @@ -0,0 +1,42 @@ +module a + +implicit none + +type, public :: MPI_Request +end type MPI_Request + +contains + +subroutine main() + integer :: s(1), d, r, v + + + type(MPI_Request) :: request_handle, handles(10) + + r= MPI_CommRank() + + call MPI_Send(d, 1, 1, 0) + + if (r==0) then + d=12 + call MPI_Isend(d, 1, 1, 0, handles(0)) + call MPI_Waitall(handles, 1) + else + call MPI_Irecv(s, 1, 0, 0, request_handle) + call MPI_Wait(request_handle) + v=s(1) + print *, v + end if + !call MPI_Waitall(handles, 2) +end subroutine main + +end module a + + +!program mpi_test +!use mpi_tester +!implicit none + +! call test() + +!end program mpi_test \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/mpi_test4.F90 b/examples/xdsl/tra_adv/code_sample/mpi_test4.F90 new file mode 100644 index 00000000000..4a90dfc49c2 --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/mpi_test4.F90 @@ -0,0 +1,40 @@ +module a + +implicit none + +type, public :: MPI_Request +end type MPI_Request + +contains + +subroutine main() + integer :: s(1), d, r, v + + + type(MPI_Request) :: request_handle, handles(10) + + r= MPI_CommRank() + + if (r==0) then + d=12 + call MPI_Isend(d, 1, 1, 0, handles(0)) + call MPI_Waitall(handles, 1) + else + call MPI_Irecv(s, 1, 0, 0, request_handle) + call MPI_Wait(request_handle) + v=s(1) + print *, v + end if + !call MPI_Waitall(handles, 2) +end subroutine main + +end module a + + +!program mpi_test +!use mpi_tester +!implicit none + +! call test() + +!end program mpi_test \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/mpi_test_2.F90 b/examples/xdsl/tra_adv/code_sample/mpi_test_2.F90 new file mode 100644 index 00000000000..930141298bf --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/mpi_test_2.F90 @@ -0,0 +1,33 @@ + + +subroutine main() + integer :: d(10), rank, recv(10), v, i + + rank=MPI_CommRank() + if (rank == 0) then + do i=1, 10 + d(i)=i + end do + call MPI_Send(d, 10, 1, 0) + print *, rank, "sent" + end if + + if (rank == 1) then + call MPI_Recv(recv, 10, 0, 0) + print *, rank, "recvd" + do i=1, 10 + v=recv(i) + print *, "Data ", i, v + end do + print *, rank, "done" + end if +end subroutine main + + +!program mpi_test +!use mpi_tester +!implicit none + +! call test() + +!end program mpi_test \ No newline at end of file diff --git a/examples/xdsl/tra_adv/code_sample/timing_test.F90 b/examples/xdsl/tra_adv/code_sample/timing_test.F90 new file mode 100644 index 00000000000..2601c8b955f --- /dev/null +++ b/examples/xdsl/tra_adv/code_sample/timing_test.F90 @@ -0,0 +1,13 @@ +subroutine main() + + integer :: itimer0, itimer1 + + call timer_init() + call timer_start(itimer0, label='Initialise') + + call timer_stop(itimer0) + call timer_start(itimer1, label='Compute') + + call timer_stop(itimer1) + call timer_report() +end subroutine main \ No newline at end of file diff --git a/examples/xdsl/tra_adv/xdsl_backends_transform.py b/examples/xdsl/tra_adv/xdsl_backends_transform.py new file mode 100644 index 00000000000..a5ab5df060f --- /dev/null +++ b/examples/xdsl/tra_adv/xdsl_backends_transform.py @@ -0,0 +1,93 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2018-2022, 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. +# ----------------------------------------------------------------------------- + +from __future__ import print_function +import sys +from psyclone.psyir.backend.fortran import FortranWriter +from psyclone.psyir.backend.xdsl import xDSLWriter +from xdsl.printer import Printer +from xdsl.dialects.builtin import ModuleOp + +def trans(psy): + #fvisitor = FortranWriter() + writer = xDSLWriter() + printer = Printer(stream=sys.stdout) + + routine_list=[] + for invoke in psy.invokes.invoke_list: + sched = invoke.schedule + + routine_list.append(writer(sched)) + + top_level=ModuleOp(routine_list) + printer.print_op(top_level) + + f = open("psy_output.mlir", "w") + p2=Printer(stream=f) + p2.print_op(top_level) + f.close() + + print("") + print("") + print("") + + ''' + print(dir(psy.container)) + print((psy.container.root)) + + tranformed=writer(psy.container) + + top_level=ModuleOp.from_region_or_ops([tranformed]) + printer.print_op(top_level) + + + schedule = psy.invokes.get('tra_adv').schedule + # This seems strange, but need to do this as each kernel is separate and we want in the same module + container_to_AST_mappings={} + for idx, kern in enumerate(schedule.kernels()): + module_name=kern.get_kernel_schedule().parent.name + if module_name in container_to_AST_mappings.keys(): + kernel_subroutine_ast=writer(kern.get_kernel_schedule()) + container_to_AST_mappings[module_name].routines.blocks[0].ops.append(kernel_subroutine_ast) + else: + container_to_AST_mappings[module_name]=writer(kern.get_kernel_schedule().parent) + + containers = [] + + for entry in container_to_AST_mappings.values(): + containers.append(entry) + containers.append(psy_layer) + top_level=ModuleOp.from_region_or_ops(containers) + printer.print_op(top_level) + ''' diff --git a/src/psyclone/psyir/backend/language_writer.py b/src/psyclone/psyir/backend/language_writer.py index 1591b8f6923..c671049a52e 100644 --- a/src/psyclone/psyir/backend/language_writer.py +++ b/src/psyclone/psyir/backend/language_writer.py @@ -144,7 +144,7 @@ def arrayreference_node(self, node): f"found: must have one or more children.") args = self.gen_indices(node.children, node.name) result = f"{node.name}{self._array_parenthesis[0]}"\ - f"{','.join(args)}{self._array_parenthesis[1]}" + f"{','.join(args)}{self._array_parenthesis[1]}" return result # ------------------------------------------------------------------------ diff --git a/src/psyclone/psyir/backend/xdsl.py b/src/psyclone/psyir/backend/xdsl.py new file mode 100644 index 00000000000..6bacc33c892 --- /dev/null +++ b/src/psyclone/psyir/backend/xdsl.py @@ -0,0 +1,680 @@ +# ----------------------------------------------------------------------------- +# BSD 3-Clause License +# +# Copyright (c) 2022, xDSL project +# +# 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. +# ----------------------------------------------------------------------------- + +'''xDSL PSyIR backend. Generates xDSL PSyclone dialect from PSyIR nodes. + +''' +from __future__ import annotations +import six +import re +from psyclone.psyir.backend.language_writer import LanguageWriter +from psyclone.psyir.backend.visitor import VisitorError +from psyclone.psyir.nodes import Routine, CodeBlock, BinaryOperation, UnaryOperation, NaryOperation, Schedule, DataNode, Range, Literal, IntrinsicCall, Statement +from psyclone.psyir.symbols import SymbolTable, ScalarType, RoutineSymbol, DataSymbol, DataTypeSymbol, ArgumentInterface, ArrayType, Symbol, NoType, UnknownFortranType, IntrinsicSymbol +from psy.dialects import psy_ir +from xdsl.dialects.builtin import StringAttr, IntAttr, ArrayAttr, i32 +from xdsl.dialects.builtin import ModuleOp +from dataclasses import dataclass, field +from typing import List, Optional, Tuple, Dict +from xdsl.ir import Operation, Attribute, ParametrizedAttribute, Region, Block, SSAValue, MLContext + +INTRINSIC_TYPE_TO_STRING={ScalarType.Intrinsic.INTEGER: "integer", ScalarType.Intrinsic.REAL: "real", + ScalarType.Intrinsic.BOOLEAN: "logical", ScalarType.Intrinsic.CHARACTER: "character"} + +INTRINSIC_FUNCTIONS=["PRINT", "TIMER_INIT", "TIMER_START", "TIMER_STOP", "TIMER_REPORT", "ALLOCATE", "DEALLOCATE"] + +@dataclass +class SSAValueCtx: + """ + Context that relates identifiers from the AST to SSA values used in the flat representation. + """ + dictionary: Dict[str, SSAValue] = field(default_factory=dict) + parent_scope: Optional[SSAValueCtx] = None + + def __getitem__(self, identifier: str) -> Optional[SSAValue]: + """Check if the given identifier is in the current scope, or a parent scope""" + ssa_value = self.dictionary.get(identifier, None) + if ssa_value: + return ssa_value + elif self.parent_scope: + return self.parent_scope[identifier] + else: + return None + + def __setitem__(self, identifier: str, ssa_value: SSAValue): + """Relate the given identifier and SSA value in the current scope""" + if identifier in self.dictionary: + raise Exception() + else: + self.dictionary[identifier] = ssa_value + +class xDSLWriter(LanguageWriter): + '''Implements a PSyIR-to-xDSL back-end for the PSyIR. + + ''' + def __init__(self, skip_nodes=False, indent_string=" ", + initial_indent_depth=0, check_global_constraints=True): + + super(xDSLWriter, self).__init__(("[", "]"), ".", skip_nodes, + indent_string, + initial_indent_depth, + check_global_constraints) + + self.global_ctx = SSAValueCtx() + self.ctx=self.global_ctx + + def apply_precision(self, precision, base_type): + if isinstance(precision, ScalarType.Precision): + if base_type.type_name.data == "real" and precision == ScalarType.Precision.DOUBLE: + base_type.set_precision(IntAttr(8)) + elif base_type.type_name.data == "real" and precision == ScalarType.Precision.SINGLE: + base_type.set_precision(IntAttr(4)) + elif base_type.type_name.data == "real" and precision == ScalarType.Precision.UNDEFINED: + base_type.set_precision(psy_ir.EmptyAttr()) + elif isinstance(precision, int): + if base_type.type_name.data not in ["real", "integer", "logical"]: + print("Error - type not compatible with precision "+base_type.name) + if base_type.type_name.data == 'real' and precision not in [4, 8, 16]: + print("Error - type 'real' supports precision of 4, 8, 16 only") + if base_type.type_name.data in ['integer', 'logical'] and precision not in \ + [1, 2, 4, 8, 16]: + print("Error - type 'integer' supports precision of 1,2, 4, 8, 16 only") + base_type.set_precision(IntAttr(precision)) + elif isinstance(precision, DataSymbol): + if base_type.type_name.data not in ["real", "integer", "logical"]: + print("Error - type not compatible with kind "+base_type.type_name.data) + base_type.set_kind(StringAttr(precision.name)) + + def gen_type(self, datatype): + if isinstance(datatype, ArrayType): + array_shape = datatype.shape + if array_shape: + dims = self.gen_indices(array_shape) + if isinstance(datatype.intrinsic, DataTypeSymbol): + base_type=psy_ir.DerivedType.from_str(datatype.intrinsic.name) + else: + base_type=psy_ir.NamedType([StringAttr(INTRINSIC_TYPE_TO_STRING[datatype.intrinsic]), psy_ir.EmptyAttr(), psy_ir.EmptyAttr()]) + self.apply_precision(datatype.precision, base_type) + return psy_ir.ArrayType.from_type_and_list(base_type, dims) + elif isinstance(datatype, DataTypeSymbol): + return psy_ir.DerivedType.from_str(datatype.name) + elif isinstance(datatype, UnknownFortranType): + print("Error - not sure how to handle unknown fortran type") + else: + base_type=psy_ir.NamedType([StringAttr(INTRINSIC_TYPE_TO_STRING[datatype.intrinsic]), psy_ir.EmptyAttr(), psy_ir.EmptyAttr()]) + self.apply_precision(datatype.precision, base_type) + return base_type + + def gen_intent(self, symbol): + mapping = {ArgumentInterface.Access.UNKNOWN: "", + ArgumentInterface.Access.READ: "in", + ArgumentInterface.Access.WRITE: "out", + ArgumentInterface.Access.READWRITE: "inout"} + + if symbol.is_argument: + return mapping[symbol.interface.access] + else: + return "" # non-Arguments do not have intent + + def gen_declarations(self, symbol_table): + var_defs = [] + + for sym in symbol_table.argument_datasymbols: + intent=self.gen_intent(sym) + var_type=self.gen_type(sym.datatype) + tkn=psy_ir.Token([StringAttr(sym.name), var_type]) + var_defs.append(psy_ir.VarDef.get(tkn, True, sym.is_constant, intent)) + self.ctx[sym.name] = tkn + + for sym in symbol_table.automatic_datasymbols: + try: + var_type=self.gen_type(sym.datatype) + tkn=psy_ir.Token([StringAttr(sym.name), var_type]) + self.ctx[sym.name] = tkn + + var_defs.append(psy_ir.VarDef.get(tkn, False, sym.is_constant)) + except (AttributeError, KeyError) as err: + raise six.raise_from(NotImplementedError( + "Could not generate the definition for the variable '{0}', " + "type '{1}' is currently not supported." + "".format(sym.name, sym.datatype)), err) + + return var_defs + + def gen_use(self, symbol, symbol_table): + # Construct the list of symbol names for the ONLY clause + only_list = [StringAttr(dsym.name) for dsym in + symbol_table.symbols_imported_from(symbol)] + + return psy_ir.Import.get(symbol.name, only_list) + + + def filecontainer_node(self, node): + program_nodes = len([child for child in node.children if + isinstance(child, Routine) and child.is_program]) + containers = [] + for child in node.children: + containers.append(self._visit(child)) + return ModuleOp.from_region_or_ops([psy_ir.FileContainer.get(node.name, containers)]) + + def container_node(self, node): + if not all(isinstance(child, (Routine, CodeBlock)) for + child in node.children): + raise VisitorError( + f"The Fortran back-end requires all children of a Container " + f"to be either CodeBlocks or sub-classes of Routine but found:" + f" {[type(child).__name__ for child in node.children]}.") + + visibility=self.gen_access_stmt(node.symbol_table) + public_routines, private_routines=self.gen_routine_access_stmts(node.symbol_table) + + imports=[] + for symbol in node.symbol_table.containersymbols: + imports.append(self.gen_use(symbol, node.symbol_table)) + + routines = [] + for child in node.children: + routines.append(self._visit(child)) + + return psy_ir.Container.get(node.name, visibility, public_routines, private_routines, imports, routines) + + def gen_access_stmt(self, symbol_table): + # If no default visibility has been set then we use the Fortran + # default of public. + if symbol_table.default_visibility in [None, Symbol.Visibility.PUBLIC]: + return self._nindent + "public" + if symbol_table.default_visibility == Symbol.Visibility.PRIVATE: + return self._nindent + "private" + + raise InternalError( + f"Unrecognised visibility ('{symbol_table.default_visibility}') " + f"found when attempting to generate access statement. Should be " + f"either 'Symbol.Visibility.PUBLIC' or " + f"'Symbol.Visibility.PRIVATE'\n") + + def gen_routine_access_stmts(self, symbol_table): + + # Find the symbol that represents itself, this one will not need + # an accessibility statement + try: + itself = symbol_table.lookup_with_tag('own_routine_symbol') + except KeyError: + itself = None + + public_routines = [] + private_routines = [] + for symbol in symbol_table.symbols: + if isinstance(symbol, RoutineSymbol): + + # Skip the symbol representing the routine where these + # declarations belong + if symbol is itself: + continue + + # It doesn't matter whether this symbol has a local or global + # interface - its accessibility in *this* context is determined + # by the local accessibility statements. e.g. if we are + # dealing with the declarations in a given module which itself + # uses a public symbol from some other module, the + # accessibility of that symbol is determined by the + # accessibility statements in the current module. + if symbol.visibility == Symbol.Visibility.PUBLIC: + public_routines.append(StringAttr(symbol.name)) + elif symbol.visibility == Symbol.Visibility.PRIVATE: + private_routines.append(StringAttr(symbol.name)) + else: + raise InternalError( + f"Unrecognised visibility ('{symbol.visibility}') " + f"found for symbol '{symbol.name}'. Should be either " + f"'Symbol.Visibility.PUBLIC' or " + f"'Symbol.Visibility.PRIVATE'.") + return public_routines, private_routines + + def routine_node(self, node): + whole_routine_scope = SymbolTable() + for schedule in node.walk(Schedule): + for symbol in schedule.symbol_table.symbols[:]: + try: + whole_routine_scope.add(symbol) + except KeyError: + new_name = whole_routine_scope.next_available_name(symbol.name) + while True: + # Ensure that the new name isn't already in the current symbol table. + local_name = schedule.symbol_table.next_available_name(new_name) + if local_name == new_name: + # new_name is availble in the current symbol table + # so we're done. + break + # new_name clashed with an entry in the current symbol + # table so try again. + new_name = whole_routine_scope.next_available_name(local_name) + schedule.symbol_table.rename_symbol(symbol, new_name) + whole_routine_scope.add(symbol) + imports.append(self.gen_use(symbol, whole_routine_scope)) + + + imports=[] + for symbol in whole_routine_scope.containersymbols: + imports.append(self.gen_use(symbol, whole_routine_scope)) + + parent_ctx=self.ctx + routine_scope_ctx = SSAValueCtx(dictionary={}, parent_scope=self.ctx) + self.ctx=routine_scope_ctx + + declarations=self.gen_declarations(whole_routine_scope) + + args = [self.ctx[symbol.name] for symbol in node.symbol_table.argument_list] + + # Get the executable statements. + exec_statements = [] + for child in node.children: + child_visited=self._visit(child) + if isinstance(child_visited, list): + exec_statements.extend(child_visited) + else: + exec_statements.append(child_visited) + + self.ctx=parent_ctx + if node.return_symbol: + # Use routine_scope_ctx as the return variable will be created in the routine so need to reference that + return psy_ir.Routine.get(node.name, routine_scope_ctx[node.return_symbol.name], imports, args, declarations, exec_statements, node.is_program) + else: + return psy_ir.Routine.get(node.name, None, imports, args, declarations, exec_statements, node.is_program) + + def codeblock_node(self, node): + # A code block can have multiple AST nodes which have not been parsed, therefore + # process each of these and store in a list that is returned at the end + ops_to_return=[] + if node.structure == CodeBlock.Structure.STATEMENT: + # indent and newlines required + for ast_node in node.get_ast_nodes: + fortran_code=ast_node.tofortran() + if fortran_code.upper().startswith("ALLOCATE"): + ops_to_return.append(self.handleAllocateCodeBlock(fortran_code)) + elif fortran_code.upper().startswith("DEALLOCATE"): + ops_to_return.append(self.handleDeAllocateCodeBlock(fortran_code)) + else: + ops_to_return.append(self.handleIntrinsic(fortran_code, False)) + elif node.structure == CodeBlock.Structure.EXPRESSION: + for ast_node in node.get_ast_nodes: + fortran_code=ast_node.tofortran() + ops_to_return.append(self.handleIntrinsic(fortran_code, True)) + else: + raise VisitorError( + f"Unsupported CodeBlock Structure '{node.structure}' found.") + return ops_to_return + + + def handleIntrinsic(self, fortran_code, isExpression): + hasToken=re.search("(^[a-zA-Z_-]*)(\s|\()+", fortran_code) + if hasToken: + psy_ir_args=[] + tokens=re.findall("(^[a-zA-Z_-]*)(\s|\()+", fortran_code) + if tokens[0][0].upper().strip() in INTRINSIC_FUNCTIONS: + arg_only=fortran_code.replace(tokens[0][0], "").replace("(", "").replace(")", "") + arguments=arg_only.split(",") + for argument in arguments: + argument=argument.strip() + if len(argument) == 0: continue + if argument.count("\"") == 2 or argument == "*": + # This is a string + psy_ir_args.append(psy_ir.Literal.get(argument)) + elif argument in self.ctx.dictionary.keys(): + # This is a variable + psy_ir_args.append(psy_ir.ExprName.get(argument, self.ctx[argument])) + else: + if self.checkIfStringIsType(argument, int): + psy_ir_args.append(psy_ir.Literal.get(int(argument), 32)) + elif self.checkIfStringIsType(argument, float): + psy_ir_args.append(psy_ir.Literal.get(float(argument), 32)) + else: + raise VisitorError(f"Unknown literal argument type '{argument}'") + if isExpression: + return psy_ir.CallExpr.get(tokens[0][0].upper().strip(), psy_ir_args, + psy_ir.NamedType([StringAttr("integer"), psy_ir.EmptyAttr(), psy_ir.EmptyAttr()]), + intrinsic=True) + else: + return psy_ir.CallExpr.get(tokens[0][0].upper().strip(), psy_ir_args, intrinsic=True) + # *** TODO: Handle module functions here + else: + #only_list = [StringAttr(dsym.name) for dsym in + # symbol_table.symbols_imported_from(symbol)] + + #if tokens[0][0].upper().strip() in only_list: + return psy_ir.CallExpr.get(tokens[0][0].upper().strip(), psy_ir_args, intrinsic=False) + #else: + # raise VisitorError(f"Intrinsic '{tokens[0][0].upper()}' call not supported") + else: + raise VisitorError(f"Can not extract intrinsic name from '{fortran_code}'") + + def checkIfStringIsType(self, string, typ): + try: + if (typ == int): + int(string) + return True + elif (typ == float): + float(string) + return True + except ValueError: + return False + raise VisitorError(f"Unknown type for string check '{str(type)}'") + + def handleDeAllocateCodeBlock(self, fortran_code): + varname=fortran_code.split("DEALLOCATE(")[1].split(")")[0] + return psy_ir.CallExpr.get("deallocate", [psy_ir.ExprName.get(varname, self.ctx[varname])], intrinsic=True) + + def handleAllocateCodeBlock(self, fortran_code): + varname=fortran_code.split("ALLOCATE(")[1].split("(")[0] + result_list=[psy_ir.ExprName.get(varname, self.ctx[varname])] + args=fortran_code.split("ALLOCATE(")[1].split("(")[1].split(")")[0].split(",") + for arg in args: + argument=arg.strip() + if argument.count("\"") == 2 or argument == "*": + raise VisitorError(f"Can not provide string as argument to allocation") + elif argument in self.ctx.dictionary.keys(): + # This is a variable + result_list.append(psy_ir.ExprName.get(argument, self.ctx[argument])) + else: + if self.checkIfStringIsType(argument, int): + result_list.append(psy_ir.Literal.get(int(argument), 32)) + elif self.checkIfStringIsType(argument, float): + result_list.append(psy_ir.Literal.get(float(argument), 32)) + else: + raise VisitorError(f"Can not interpret argument `{argument}` in allocation") + + return psy_ir.CallExpr.get("allocate", result_list, intrinsic=True) + + def nemokern_node(self, node): + exec_statements = [] + schedule = node.get_kernel_schedule() + for child in schedule.children: + exec_statements.append(self._visit(child)) + return exec_statements + + def assignment_node(self, node): + visited_rhs=self._visit(node.rhs) + if isinstance(visited_rhs, list): + assert len(visited_rhs) == 1 + visited_rhs=visited_rhs[0] + return psy_ir.Assign.get(self._visit(node.lhs), visited_rhs) + + def reference_node(self, node): + return psy_ir.ExprName.get(node.symbol.name, self.ctx[node.symbol.name]) + + def structurereference_node(self, node): + return psy_ir.StructureReference.get(self.ctx[node.symbol.name], self._visit(node.children[0])) + + def member_node(self, node): + if not node.children: + return psy_ir.StructureMember([StringAttr(node.name), psy_ir.EmptyAttr()]) + else: + return psy_ir.StructureMember([StringAttr(node.name), self._visit(node.children[0])]) + + def return_node(self, node): + return psy_ir.Return() + + def arrayreference_node(self, node): + if not node.children: + raise VisitorError( + "Incomplete ArrayReference node (for symbol '{0}') found: " + "must have one or more children.".format(node.name)) + + args = self.gen_indices(node.children, node.name) + # For allocate intrinsic call, remove the arg range wrapper + #if node.parent: + # if isinstance(node.parent, IntrinsicCall): + # *** TODO: We should check for "ALLOCATE" here + # args = [] + # args.append(psy_ir.ExprName.get(node.symbol.name, self.ctx[node.symbol.name])) + # for kid in node.children: + # if isinstance(kid, Range): + # if not isinstance(kid.stop, Literal): + # args.append(psy_ir.ExprName.get(kid.stop.name, self.ctx[kid.stop.name])) + # kid.stop._parent = None + # node.parent.addchild(kid.stop) + # return psy_ir.ExprName.get(node.symbol.name, self.ctx[node.symbol.name]) + return psy_ir.ArrayReference.get(self.ctx[node.name], args) + + + def gen_indices(self, indices, var_name=None): + dims = [] + for index in indices: + if isinstance(index, (DataNode, Range)): + # literal constant, symbol reference, or computed dimension + expression = self._visit(index) + dims.append(expression) + elif isinstance(index, ArrayType.Extent) and index == ArrayType.Extent.DEFERRED: + dims.append(psy_ir.DeferredAttr()) + elif isinstance(index, ArrayType.Extent) and index == ArrayType.Extent.ATTRIBUTE: + dims.append(psy_ir.AssumedSizeAttr()) + elif isinstance(index, ArrayType.ArrayBounds): + expression = self._visit(index.lower) + if isinstance(expression, psy_ir.Literal): + dims.append(expression.value) + else: + dims.append(expression) + expression = self._visit(index.upper) + if isinstance(expression, psy_ir.Literal): + dims.append(expression.value) + else: + dims.append(expression) + else: + raise NotImplementedError(f"unsupported gen_indices index '{index}'") + return dims + + def loop_node(self, node): + start = self._visit(node.start_expr) + stop = self._visit(node.stop_expr) + step = self._visit(node.step_expr) + + body = [] + for child in node.loop_body: + child_contents=self._visit(child) + if isinstance(child_contents, list): + body.extend(child_contents) + else: + body.append(child_contents) + + return psy_ir.Loop.get(self.ctx[node.variable.name], start, stop, step, body) + + def ifblock_node(self, node): + condition = self._visit(node.children[0]) + + if_body = [] + for child in node.if_body: + if_body.append(self._visit(child)) + + else_body = [] + # node.else_body is None if there is no else clause. + if node.else_body: + for child in node.else_body: + else_body.append(self._visit(child)) + + return psy_ir.IfBlock.get(condition, if_body, else_body) + + def binaryoperation_node(self, node): + if len(node.children) != 2: + raise VisitorError( + "BinaryOperation malformed or incomplete. It " + "should have exactly 2 children, but found {0}." + "".format(len(node.children))) + + opmap = { + BinaryOperation.Operator.ADD: "ADD", + BinaryOperation.Operator.SUB: "SUB", + BinaryOperation.Operator.MUL: "MUL", + BinaryOperation.Operator.DIV: "DIV", + BinaryOperation.Operator.REM: "REM", + BinaryOperation.Operator.POW: "POW", + BinaryOperation.Operator.SUM: "SUM", + BinaryOperation.Operator.EQ: "EQ", + BinaryOperation.Operator.NE: "NE", + BinaryOperation.Operator.LT: "LT", + BinaryOperation.Operator.LE: "LE", + BinaryOperation.Operator.GT: "GT", + BinaryOperation.Operator.GE: "GE", + BinaryOperation.Operator.AND: "AND", + BinaryOperation.Operator.OR: "OR", + BinaryOperation.Operator.SIGN: "SIGN", + BinaryOperation.Operator.MIN: "MIN", + BinaryOperation.Operator.MAX: "MAX", + BinaryOperation.Operator.REAL: "REAL", + BinaryOperation.Operator.INT: "INT", + BinaryOperation.Operator.CAST: "CAST", + BinaryOperation.Operator.SIZE: "SIZE", + BinaryOperation.Operator.LBOUND: "LBOUND", + BinaryOperation.Operator.UBOUND: "UBOUND", + BinaryOperation.Operator.MATMUL: "MATMUL", + BinaryOperation.Operator.DOT_PRODUCT: "DOT_PRODUCT", + } + + # For now ignore this, pow and copysign are functions so need to be call expressio rather than binary expression in dialect + try: + opstring=opmap[node.operator] + except KeyError as err: + raise six.raise_from(VisitorError( + "The xDSL backend does not support the '{0}' operator." + "".format(node.operator)), err) + return psy_ir.BinaryOperation.get(opstring, self._visit(node.children[0]), self._visit(node.children[1])) + + def unaryoperation_node(self, node): + if len(node.children) != 1: + raise VisitorError( + "UnaryOperation malformed or incomplete. It " + "should have exactly 1 children, but found {0}." + "".format(len(node.children))) + + opmap = { + UnaryOperation.Operator.MINUS: "MINUS", + UnaryOperation.Operator.PLUS: "PLUS", + UnaryOperation.Operator.SQRT: "SQRT", + UnaryOperation.Operator.EXP: "EXP", + UnaryOperation.Operator.LOG: "LOG", + UnaryOperation.Operator.LOG10: "LOG10", + UnaryOperation.Operator.SUM: "SUM", + UnaryOperation.Operator.NOT: "NOT", + UnaryOperation.Operator.COS: "COS", + UnaryOperation.Operator.SIN: "SIN", + UnaryOperation.Operator.TAN: "TAN", + UnaryOperation.Operator.ACOS: "ACOS", + UnaryOperation.Operator.ASIN: "ASIN", + UnaryOperation.Operator.ATAN: "ATAN", + UnaryOperation.Operator.ABS: "ABS", + UnaryOperation.Operator.CEIL: "CEIL", + UnaryOperation.Operator.REAL: "REAL", + UnaryOperation.Operator.INT: "INT", + UnaryOperation.Operator.NINT: "NINT", + } + + # For now ignore this, pow and copysign are functions so need to be call expressio rather than binary expression in dialect + try: + opstring=opmap[node.operator] + except KeyError as err: + raise six.raise_from(VisitorError( + "The xDSL backend does not support the '{0}' operator." + "".format(node.operator)), err) + return psy_ir.UnaryOperation.get(opstring, self._visit(node.children[0])) + + def naryoperation_node(self, node): + opmap = { + NaryOperation.Operator.MIN: "MIN", + NaryOperation.Operator.MAX: "MAX", + NaryOperation.Operator.SUM: "SUM" + } + + arg_expr_list = [] + for child in node.children: + arg_expr_list.append(self._visit(child)) + try: + opstring=opmap[node.operator] + except KeyError as error: + raise VisitorError( + f"Unexpected N-ary op '{node.operator}'") from error + return psy_ir.NaryOperation.get(opstring, arg_expr_list) + + def literal_node(self, node): + if (node.datatype.precision == ScalarType.Precision.SINGLE): + width=32 + elif (node.datatype.precision == ScalarType.Precision.DOUBLE): + width=64 + elif isinstance(node.datatype.precision, int): + width=node.datatype.precision * 8 + else: + width=32 + if isinstance(node.datatype, ScalarType): + if node.datatype.intrinsic == ScalarType.Intrinsic.INTEGER: + return psy_ir.Literal.get(int(node.value), width) + elif node.datatype.intrinsic == ScalarType.Intrinsic.REAL: + return psy_ir.Literal.get(float(node.value), width) + + return psy_ir.Literal.get(node.value) + + def range_node(self, node): + if node.parent and node.parent.is_lower_bound( + node.parent.indices.index(node)): + # The range starts for the first element in this + # dimension. This is the default in Fortran so no need to + # output anything. + start = [] + else: + start = [self._visit(node.start)] + + if node.parent and node.parent.is_upper_bound( + node.parent.indices.index(node)): + # The range ends with the last element in this + # dimension. This is the default in Fortran so no need to + # output anything. + stop = [] + else: + stop = [self._visit(node.stop)] + + if isinstance(node.step, Literal) and \ + node.step.datatype.intrinsic == ScalarType.Intrinsic.INTEGER and \ + node.step.value == "1": + + step=[] + else: + step = [self._visit(node.step)] + return psy_ir.Range.get(start, stop, step) + + def call_node(self, node): + result_list = [] + for child in node.children: + result_list.append(self._visit(child)) + + intrinsic=isinstance(node.routine, IntrinsicSymbol) + + if isinstance(node.routine.datatype, NoType): + return psy_ir.CallExpr.get(node.routine.name, result_list, intrinsic=intrinsic) + else: + return psy_ir.CallExpr.get(node.routine.name, result_list, self.gen_type(node.routine.datatype), intrinsic=intrinsic) diff --git a/src/psyclone/psyir/nodes/__init__.py b/src/psyclone/psyir/nodes/__init__.py index 7b336214cf3..066b7007480 100644 --- a/src/psyclone/psyir/nodes/__init__.py +++ b/src/psyclone/psyir/nodes/__init__.py @@ -55,7 +55,7 @@ from psyclone.psyir.nodes.array_of_structures_member import \ ArrayOfStructuresMember from psyclone.psyir.nodes.operation import Operation, UnaryOperation, \ - BinaryOperation + BinaryOperation, NaryOperation from psyclone.psyir.nodes.literal import Literal from psyclone.psyir.nodes.if_block import IfBlock from psyclone.psyir.nodes.intrinsic_call import IntrinsicCall @@ -117,6 +117,7 @@ 'Literal', 'Loop', 'Member', + 'NaryOperation', 'Node', 'OperandClause', 'Operation', diff --git a/src/psyclone/psyir/nodes/operation.py b/src/psyclone/psyir/nodes/operation.py index 8a6978bf48f..ac129653641 100644 --- a/src/psyclone/psyir/nodes/operation.py +++ b/src/psyclone/psyir/nodes/operation.py @@ -139,11 +139,19 @@ class UnaryOperation(Operation): Operator = Enum('Operator', [ # Arithmetic Operators - 'MINUS', 'PLUS', + 'MINUS', 'PLUS', 'SQRT', 'EXP', 'LOG', 'LOG10', 'SUM', # Logical Operators 'NOT', + # Trigonometric Operators + 'COS', 'SIN', 'TAN', 'ACOS', 'ASIN', 'ATAN', + # Other Maths Operators + 'ABS', 'CEIL', + # Casting Operators + 'REAL', 'INT', 'NINT' ]) + _non_elemental_ops = [Operator.SUM] + @staticmethod def _validate_child(position, child): ''' @@ -196,12 +204,95 @@ class BinaryOperation(Operation): ''' Operator = Enum('Operator', [ # Arithmetic Operators. ('REM' is remainder AKA 'MOD' in Fortran.) - 'ADD', 'SUB', 'MUL', 'DIV', 'REM', 'POW', + 'ADD', 'SUB', 'MUL', 'DIV', 'REM', 'POW', 'SUM', # Relational Operators 'EQ', 'NE', 'GT', 'LT', 'GE', 'LE', # Logical Operators 'AND', 'OR', 'EQV', 'NEQV', + # Other Maths Operators + 'SIGN', 'MIN', 'MAX', + # Casting operators + 'REAL', 'INT', 'CAST', + # Array Query Operators + 'SIZE', 'LBOUND', 'UBOUND', + # Matrix and Vector Operators + 'MATMUL', 'DOT_PRODUCT' ]) + _non_elemental_ops = [Operator.SUM, Operator.MATMUL, Operator.SIZE, + Operator.LBOUND, Operator.UBOUND, + Operator.DOT_PRODUCT] + '''Arithmetic operators: + + .. function:: POW(arg0, arg1) -> type(arg0) + + :returns: `arg0` raised to the power of `arg1`. + + Array query operators: + + .. function:: SIZE(array, index) -> int + + :returns: the size of the `index` dimension of `array`. + + .. function:: LBOUND(array, index) -> int + + :returns: the value of the lower bound of the `index` dimension of \ + `array`. + + .. function:: UBOUND(array, index) -> int + + :returns: the value of the upper bound of the `index` dimension of \ + `array`. + + Casting Operators: + + .. function:: REAL(arg0, precision) + + :returns: `arg0` converted to a floating point number of the \ + specified precision. + + .. function:: INT(arg0, precision) + + :returns: `arg0` converted to an integer number of the specified \ + precision. + + .. function:: CAST(arg0, mold) + + :returns: `arg0` with the same bitwise representation but interpreted \ + with the same type as the specified `mold` argument. + + Matrix and Vector Operators: + + .. function:: MATMUL(array1, array2) -> array + + :returns: the result of performing a matrix multiply with a \ + matrix (`array1`) and a matrix or a vector + (`array2`). + + .. note:: `array1` must be a 2D array. `array2` may be a 2D array + or a 1D array (vector). The size of the second dimension of + `array1` must be the same as the first dimension of + `array1`. If `array2` is 2D then the resultant array will be + 2D with the size of its first dimension being the same as the + first dimension of `array1` and the size of its second + dimension being the same as second dimension of `array2`. If + `array2` is a vector then the resultant array is a vector with + the its size being the size of the first dimension of + `array1`. + + .. note:: The type of data in `array1` and `array2` must be the + same and the resultant data will also have the same + type. Currently only REAL data is supported. + + .. function:: DOT_PRODUCT(vector1, vector2) -> scalar + + :returns: the result of performing a dot product on two equal \ + sized vectors. + + .. note:: The type of data in `vector1` and `vector2` must be the + same and the resultant data will also have the same + type. Currently only REAL data is supported. + + ''' # Textual description of the node. _children_valid_format = "DataNode, DataNode" @@ -257,5 +348,86 @@ def create(operator, lhs, rhs): return binary_op +class NaryOperation(Operation): + '''Node representing a n-ary operation expression. The n operands are + the stored as the 0 - n-1th children of this node and the type of + the operator is held in an attribute. + + ''' + # Textual description of the node. + _children_valid_format = "[DataNode]+" + _text_name = "NaryOperation" + + Operator = Enum('Operator', [ + # Arithmetic Operators + 'MAX', 'MIN', 'SUM' + ]) + _non_elemental_ops = [Operator.SUM] + + @staticmethod + def _validate_child(position, child): + ''' + :param int position: the position to be validated. + :param child: a child to be validated. + :type child: :py:class:`psyclone.psyir.nodes.Node` + + :return: whether the given child and position are valid for this node. + :rtype: bool + + ''' + # pylint: disable=unused-argument + return isinstance(child, DataNode) + + @staticmethod + def create(operator, operands): + '''Create an NaryOperator instance given an operator and a list of + Node (or name and Node tuple) instances. + + :param operator: the operator used in the operation. + :type operator: :py:class:`psyclone.psyir.nodes.NaryOperation.Operator` + :param operands: a list containing PSyIR nodes and/or 2-tuples \ + which contain an argument name and a PSyIR node, that the \ + operator operates on. + :type operands: List[Union[:py:class:`psyclone.psyir.nodes.Node`, \ + Tuple[str, :py:class:`psyclone.psyir.nodes.DataNode`]]] + + :returns: an NaryOperator instance. + :rtype: :py:class:`psyclone.psyir.nodes.NaryOperation` + + :raises GenerationError: if the arguments to the create method \ + are not of the expected type. + + ''' + if not isinstance(operator, Enum) or \ + operator not in NaryOperation.Operator: + raise GenerationError( + f"operator argument in create method of NaryOperation class " + f"should be a PSyIR NaryOperation Operator but found " + f"'{type(operator).__name__}'.") + if not isinstance(operands, list): + raise GenerationError( + f"operands argument in create method of NaryOperation class " + f"should be a list but found '{type(operands).__name__}'.") + + nary_op = NaryOperation(operator) + for operand in operands: + name = None + if isinstance(operand, tuple): + if not len(operand) == 2: + raise GenerationError( + f"If an element of the operands argument in create " + f"method of NaryOperation class is a tuple, it's " + f"length should be 2, but found {len(operand)}.") + if not isinstance(operand[0], str): + raise GenerationError( + f"If an element of the operands argument in create " + f"method of NaryOperation class is a tuple, " + f"its first argument should be a str, but found " + f"{type(operand[0]).__name__}.") + name, operand = operand + nary_op.append_named_arg(name, operand) + return nary_op + + # For automatic API documentation generation -__all__ = ["Operation", "UnaryOperation", "BinaryOperation"] +__all__ = ["Operation", "UnaryOperation", "BinaryOperation", "NaryOperation"] diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/field_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/field_mod.f90 index 8efaeb93257..69dc25490e5 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/field_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/field_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -51,15 +49,15 @@ module field_mod ! Eventually the precision of the field data will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from field_mod, so it is set here - - - - - +#if (RDEF_PRECISION == 32) + use field_r32_mod, only: field_type => field_r32_type, & + field_proxy_type => field_r32_proxy_type, & + field_pointer_type => field_r32_pointer_type +#else use field_r64_mod, only: field_type => field_r64_type, & field_proxy_type => field_r64_proxy_type, & field_pointer_type => field_r64_pointer_type - +#endif implicit none private diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/master_dofmap_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/master_dofmap_mod.f90 index fa64ac27981..1bfe4a6395f 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/master_dofmap_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/master_dofmap_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_face_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_face_mod.f90 index b15d5629259..e5932d536bc 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_face_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_face_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (c) Crown copyright 2018-2020 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_mod.f90 index a4813dfaa93..6a3d9037e16 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2017-2020 Met Office. All rights reserved. ! For further details please refer to the file LICENCE which you should have diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_rule_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_rule_mod.f90 index 707f35a04d3..f52721a50b3 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_rule_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_rule_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xoyoz_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xoyoz_mod.f90 index 494f6f2166e..2374c06bdbd 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xoyoz_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xoyoz_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2017-2020 Met Office. All rights reserved. ! For further details please refer to the file LICENCE which you should have diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyoz_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyoz_mod.f90 index c71e060504c..987712dd15d 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyoz_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyoz_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2017-2020 Met Office. All rights reserved. ! For further details please refer to the file LICENCE which you should have diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyz_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyz_mod.f90 index 132d280d474..3f595fc96b0 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyz_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/quadrature_xyz_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2017-2020 Met Office. All rights reserved. ! For further details please refer to the file LICENCE which you should have diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_phys_field_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_phys_field_mod.f90 index 997da8028b0..6c0391674ed 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_phys_field_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_phys_field_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2023 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -51,15 +49,15 @@ module r_phys_field_mod ! Eventually the precision of the field data will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from field_mod, so it is set here - - - - - +#if (R_PHYS_PRECISION == 32) + use field_r32_mod, only: r_phys_field_type => field_r32_type, & + r_phys_field_proxy_type => field_r32_proxy_type, & + r_phys_field_pointer_type => field_r32_pointer_type +#else use field_r64_mod, only: r_phys_field_type => field_r64_type, & r_phys_field_proxy_type => field_r64_proxy_type, & r_phys_field_pointer_type => field_r64_pointer_type - +#endif implicit none private diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_solver_field_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_solver_field_mod.f90 index f593d836e58..97fa2e123c3 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_solver_field_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_solver_field_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -51,15 +49,15 @@ module r_solver_field_mod ! Eventually the precision of the field data will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from field_mod, so it is set here - - - - - +#if (R_SOLVER_PRECISION == 32) + use field_r32_mod, only: r_solver_field_type => field_r32_type, & + r_solver_field_proxy_type => field_r32_proxy_type, & + r_solver_field_pointer_type => field_r32_pointer_type +#else use field_r64_mod, only: r_solver_field_type => field_r64_type, & r_solver_field_proxy_type => field_r64_proxy_type, & r_solver_field_pointer_type => field_r64_pointer_type - +#endif implicit none private diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_tran_field_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_tran_field_mod.f90 index 980cf2ba7fa..c348db3ae65 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_tran_field_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/r_tran_field_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -52,15 +50,15 @@ module r_tran_field_mod ! Eventually the precision of the field data will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from field_mod, so it is set here - - - - - +#if (R_TRAN_PRECISION == 32) + use field_r32_mod, only: r_tran_field_type => field_r32_type, & + r_tran_field_proxy_type => field_r32_proxy_type, & + r_tran_field_pointer_type => field_r32_pointer_type +#else use field_r64_mod, only: r_tran_field_type => field_r64_type, & r_tran_field_proxy_type => field_r64_proxy_type, & r_tran_field_pointer_type => field_r64_pointer_type - +#endif implicit none private diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/stencil_dofmap_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/stencil_dofmap_mod.f90 index b5699884adc..caef7adf676 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/stencil_dofmap_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/field/stencil_dofmap_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/function_space/function_space_constructor_helper_functions_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/function_space/function_space_constructor_helper_functions_mod.f90 index f15cbdc0ee4..3aed3d842b4 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/function_space/function_space_constructor_helper_functions_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/function_space/function_space_constructor_helper_functions_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_2d_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_2d_mod.f90 index bb600bebfe7..aa7752861e6 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_2d_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_2d_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_file_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_file_mod.f90 index 4b52b838283..90af011cf0c 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_file_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/io/ugrid_file_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/global_mesh_base_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/global_mesh_base_mod.f90 index da06938f08a..73660238c8e 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/global_mesh_base_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/global_mesh_base_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/mesh_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/mesh_mod.f90 index f8db308fb4e..dfdc3d4fd85 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/mesh_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/mesh/mesh_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2021, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/operator_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/operator_mod.f90 index 6c116348153..4e9589a2521 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/operator_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/operator_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -51,13 +49,13 @@ module operator_mod ! Eventually the precision of the operator will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from operator_mod, so it is set here - - - - +#if (RDEF_PRECISION == 32) + use operator_r32_mod, only: operator_type => operator_r32_type, & + operator_proxy_type => operator_r32_proxy_type +#else use operator_r64_mod, only: operator_type => operator_r64_type, & operator_proxy_type => operator_r64_proxy_type - +#endif use r_solver_operator_mod, only: r_solver_operator_type, & r_solver_operator_proxy_type diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/r_solver_operator_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/r_solver_operator_mod.f90 index 6d522a93a91..7654ae9dbea 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/r_solver_operator_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/operator/r_solver_operator_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -50,13 +48,13 @@ module r_solver_operator_mod ! Eventually the precision of the operator will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from operator_mod, so it is set here - - - - +#if (R_SOLVER_PRECISION == 32) + use operator_r32_mod, only: r_solver_operator_type => operator_r32_type, & + r_solver_operator_proxy_type => operator_r32_proxy_type +#else use operator_r64_mod, only: r_solver_operator_type => operator_r64_type, & r_solver_operator_proxy_type => operator_r64_proxy_type - +#endif implicit none ! Removing the following "private" statement is a workaround for a bug that diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/scalar/scalar_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/scalar/scalar_mod.f90 index 7ba57e26935..a98b10cbc86 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/scalar/scalar_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/scalar/scalar_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2022 Met Office. All rights reserved. ! The file LICENCE, distributed with this code, contains details of the terms @@ -18,11 +16,11 @@ module scalar_mod ! Eventually the precision of the scalar will be set in a module held ! within the model (as it is model information). For now, PSyclone is ! expecting to "use" the definitions from scalar_mod, so it is set here - - - +#if (RDEF_PRECISION == 32) + use scalar_r32_mod, only: scalar_type => scalar_r32_type +#else use scalar_r64_mod, only: scalar_type => scalar_r64_type - +#endif implicit none private diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/linked_list_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/linked_list_mod.f90 index 11753244b7a..c0ef1d8ace7 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/linked_list_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/linked_list_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! Copyright (c) 2017-2020, Met Office, on behalf of HMSO and Queen's Printer ! For further details please refer to the file LICENCE.original which you diff --git a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/timer_mod.f90 b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/timer_mod.f90 index 9b2da4ca6d2..5c26979d7c4 100644 --- a/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/timer_mod.f90 +++ b/src/psyclone/tests/test_files/dynamo0p3/infrastructure/utilities/timer_mod.f90 @@ -1,5 +1,3 @@ - - !----------------------------------------------------------------------------- ! (C) Crown copyright 2017 Met Office. All rights reserved. ! For further details please refer to the file LICENCE which you should have