Skip to content

Commit

Permalink
#1823 Bring to master
Browse files Browse the repository at this point in the history
  • Loading branch information
sergisiso committed Sep 30, 2022
2 parents a9f08a0 + 5170f07 commit e6e3842
Show file tree
Hide file tree
Showing 37 changed files with 1,792 additions and 511 deletions.
15 changes: 15 additions & 0 deletions changelog
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,21 @@
47) PR #1890 for #1889. Fix test to avoid temporary files being
left after pytest run.

48) PR #1850 towards #1799. Initial PSyIR node.datatype implementation
to query the resulting datatype of a PSyIR subtree.

49) PR #1869 for #1868. Extend PSyAD to make use of the
Reference2ArrayRangeTrans.

50) PR #1880 for #1865. Improves support for function calls in the
PSyIR by ensuring the associated RoutineSymbol has the correct
datatype.

51) PR #1894 for #1893. Fix bug in is_upper/lower_bound for UnknownTypes.

52) PR #1853 for #1829. Add OMP teams distribute parallel do directive
and refactor OMPLoopTrans.

release 2.3.1 17th of June 2022

1) PR #1747 for #1720. Adds support for If blocks to PSyAD.
Expand Down
4 changes: 2 additions & 2 deletions doc/user_guide/transformations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,8 @@ can be found in the API-specific sections).

####

.. autoclass:: psyclone.transformations.OMPLoopTrans
:members: apply, omp_schedule, omp_worksharing
.. autoclass:: psyclone.psyir.transformations.OMPLoopTrans
:members: apply, omp_schedule, omp_directive
:noindex:

####
Expand Down
8 changes: 3 additions & 5 deletions examples/nemo/eg1/openmp_gpu_trans.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@

from psyclone.psyir.nodes import Loop, Assignment
from psyclone.domain.nemo.transformations import NemoAllArrayRange2LoopTrans
from psyclone.psyir.transformations.omp_target_trans import OMPTargetTrans
from psyclone.transformations import TransformationError, OMPLoopTrans
from psyclone.psyir.transformations import OMPTargetTrans, OMPLoopTrans
from psyclone.transformations import TransformationError

USE_GPU = True # Enable for generating OpenMP target directives

Expand All @@ -57,9 +57,7 @@ def trans(psy):
'''
omp_target_trans = OMPTargetTrans()
omp_loop_trans = OMPLoopTrans()
# Disabling worksharing will produce the 'loop' directive which is better
# suited to map the work into the GPU
omp_loop_trans.omp_worksharing = False
omp_loop_trans.omp_directive = "loop"

print("Invokes found:")
for invoke in psy.invokes.invoke_list:
Expand Down
Binary file modified psyclone.pdf
Binary file not shown.
14 changes: 12 additions & 2 deletions src/psyclone/psyad/transformations/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@
'''
from psyclone.core import SymbolicMaths
from psyclone.psyad.utils import node_is_active, node_is_passive
from psyclone.psyir.nodes import BinaryOperation, Assignment, Range
from psyclone.psyir.nodes import BinaryOperation, Assignment, Range, \
Reference
from psyclone.psyir.transformations import DotProduct2CodeTrans, \
Matmul2CodeTrans, ArrayRange2LoopTrans, TransformationError
Matmul2CodeTrans, ArrayRange2LoopTrans, TransformationError, \
Reference2ArrayRangeTrans


def preprocess_trans(kernel_psyir, active_variable_names):
Expand All @@ -63,6 +65,14 @@ def preprocess_trans(kernel_psyir, active_variable_names):
dot_product_trans = DotProduct2CodeTrans()
matmul_trans = Matmul2CodeTrans()
arrayrange2loop_trans = ArrayRange2LoopTrans()
reference2arrayrange_trans = Reference2ArrayRangeTrans()

# Replace references to arrays (array notation) with array-ranges
for reference in kernel_psyir.walk(Reference):
try:
reference2arrayrange_trans.apply(reference)
except TransformationError:
pass

# Replace array-ranges with explicit loops
for assignment in kernel_psyir.walk(Assignment):
Expand Down
33 changes: 26 additions & 7 deletions src/psyclone/psyir/frontend/fparser2.py
Original file line number Diff line number Diff line change
Expand Up @@ -3523,7 +3523,7 @@ def _name_handler(self, node, parent):
'''
symbol = _find_or_create_imported_symbol(parent, node.string)
return Reference(symbol, parent)
return Reference(symbol, parent=parent)

def _parenthesis_handler(self, node, parent):
'''
Expand Down Expand Up @@ -3554,11 +3554,12 @@ def _part_ref_handler(self, node, parent):
:param parent: Parent node of the PSyIR node we are constructing.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:raises NotImplementedError: If the fparser node represents \
:raises NotImplementedError: if the fparser node represents \
unsupported PSyIR features and should be placed in a CodeBlock.
:returns: PSyIR representation of node
:rtype: :py:class:`psyclone.psyir.nodes.ArrayReference`
:returns: the PSyIR node.
:rtype: :py:class:`psyclone.psyir.nodes.ArrayReference` or \
:py:class:`psyclone.psyir.nodes.Call`
'''
reference_name = node.items[0].string.lower()
Expand All @@ -3567,9 +3568,12 @@ def _part_ref_handler(self, node, parent):
# part-references instead of function-references.
symbol = _find_or_create_imported_symbol(parent, reference_name)

array = ArrayReference(symbol, parent)
self.process_nodes(parent=array, nodes=node.items[1].items)
return array
if isinstance(symbol, RoutineSymbol):
call_or_array = Call(symbol, parent=parent)
else:
call_or_array = ArrayReference(symbol, parent=parent)
self.process_nodes(parent=call_or_array, nodes=node.items[1].items)
return call_or_array

def _subscript_triplet_handler(self, node, parent):
'''
Expand Down Expand Up @@ -3907,6 +3911,21 @@ def _subroutine_handler(self, node, parent):
# attempt to recreate the prefix. We have to set shadowing to
# True as there is likely to be a RoutineSymbol for this
# function in any enclosing Container.

# First, update the existing RoutineSymbol with the
# return datatype specified in the function
# declaration.

# Lookup with the routine name as return_name may be
# declared with its own local name. Be wary that this
# function may not be referenced so there might not be
# a RoutineSymbol.
try:
routine_symbol = routine.symbol_table.lookup(routine.name)
routine_symbol.datatype = base_type
except KeyError:
pass

routine.symbol_table.new_symbol(return_name,
tag=keep_tag,
symbol_type=DataSymbol,
Expand Down
4 changes: 3 additions & 1 deletion src/psyclone/psyir/nodes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@
OMPParallelDirective, OMPParallelDoDirective, OMPSingleDirective, \
OMPMasterDirective, OMPSerialDirective, OMPTaskloopDirective, \
OMPTaskwaitDirective, OMPStandaloneDirective, OMPRegionDirective, \
OMPTargetDirective, OMPLoopDirective, OMPDeclareTargetDirective
OMPTargetDirective, OMPLoopDirective, OMPDeclareTargetDirective, \
OMPTeamsDistributeParallelDoDirective
from psyclone.psyir.nodes.clause import Clause, OperandClause
from psyclone.psyir.nodes.omp_clauses import OMPGrainsizeClause, \
OMPNogroupClause, OMPNowaitClause, OMPNumTasksClause, OMPPrivateClause, \
Expand Down Expand Up @@ -161,6 +162,7 @@
'OMPTargetDirective',
'OMPLoopDirective',
'OMPDeclareTargetDirective',
'OMPTeamsDistributeParallelDoDirective',
# OMP Clause Nodes
'OMPGrainsizeClause',
'OMPNogroupClause',
Expand Down
91 changes: 85 additions & 6 deletions src/psyclone/psyir/nodes/array_mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,22 @@
''' This module contains the implementation of the abstract ArrayMixin. '''

import abc
import six

from psyclone.errors import InternalError
from psyclone.psyir.nodes.call import Call
from psyclone.psyir.nodes.codeblock import CodeBlock
from psyclone.psyir.nodes.datanode import DataNode
from psyclone.psyir.nodes.literal import Literal
from psyclone.psyir.nodes.member import Member
from psyclone.psyir.nodes.operation import BinaryOperation
from psyclone.psyir.nodes.operation import Operation, BinaryOperation
from psyclone.psyir.nodes.ranges import Range
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.symbols import SymbolError
from psyclone.psyir.symbols.datatypes import ScalarType, ArrayType
from psyclone.psyir.symbols.datatypes import (ScalarType, ArrayType,
INTEGER_TYPE)


@six.add_metaclass(abc.ABCMeta)
class ArrayMixin(object):
class ArrayMixin(metaclass=abc.ABCMeta):
'''
Abstract class used to add functionality common to Nodes that represent
Array accesses.
Expand Down Expand Up @@ -95,7 +96,7 @@ def get_signature_and_indices(self):
:rtype: tuple(:py:class:`psyclone.core.Signature`, list of \
lists of indices)
'''
sig, _ = super(ArrayMixin, self).get_signature_and_indices()
sig, _ = super().get_signature_and_indices()
return (sig, [self.indices[:]])

def _validate_index(self, index):
Expand Down Expand Up @@ -151,6 +152,10 @@ def is_lower_bound(self, index):
try:
symbol = self.scope.symbol_table.lookup(self.name)
datatype = symbol.datatype
# Check that the symbol is of ArrayType. (It may be of
# UnknownFortranType if the symbol is of e.g. character type.)
if not isinstance(datatype, ArrayType):
return False
shape = datatype.shape
array_bounds = shape[index]
if (isinstance(array_bounds, ArrayType.ArrayBounds)
Expand Down Expand Up @@ -211,6 +216,10 @@ def is_upper_bound(self, index):
try:
symbol = self.scope.symbol_table.lookup(self.name)
datatype = symbol.datatype
# Check that the symbol is of ArrayType. (It may be of
# UnknownFortranType if the symbol is of e.g. character type.)
if not isinstance(datatype, ArrayType):
return False
shape = datatype.shape
array_bounds = shape[index]
if (isinstance(array_bounds, ArrayType.ArrayBounds) and
Expand Down Expand Up @@ -355,6 +364,76 @@ def indices(self):
f"expression but found '{type(child).__name__}'")
return self.children

def _get_effective_shape(self):
'''
:returns: the shape of the array access represented by this node.
:rtype: List[:py:class:`psyclone.psyir.nodes.DataNode`]
:raises NotImplementedError: if any of the array-indices involve a
function call or an expression.
'''
def _num_elements(expr):
'''
Create PSyIR for the number of elements in this range. It
is given by (stop - start)/step + 1.
:param expr: the range for which to compute the number of elements.
:type expr: :py:class:`psyclone.psyir.nodes.Range` or \
:py:class:`psyclone.psyir.symbols.ArrayType.ArrayBounds`
:returns: the PSyIR expression for the number of elements in the \
supplied range.
:rtype: :py:class:`psyclone.psyir.nodes.BinaryOperation`
'''
if isinstance(expr, Range):
start = expr.start
stop = expr.stop
step = expr.step
elif isinstance(expr, ArrayType.ArrayBounds):
start = expr.lower
stop = expr.upper
step = Literal("1", INTEGER_TYPE)
minus = BinaryOperation.create(BinaryOperation.Operator.SUB,
stop.copy(), start.copy())
div = BinaryOperation.create(BinaryOperation.Operator.DIV,
minus, step.copy())
plus = BinaryOperation.create(BinaryOperation.Operator.ADD,
div, Literal("1", INTEGER_TYPE))
return plus

shape = []
for idx_expr in self.indices:
if isinstance(idx_expr, Range):
shape.append(_num_elements(idx_expr))

elif isinstance(idx_expr, Reference):
dtype = idx_expr.datatype
if dtype.shape:
# An array slice can be defined by a 1D slice of another
# array, e.g. `a(b(1:4))`.
if len(dtype.shape) > 1:
raise InternalError(
f"An array defining a slice of a dimension of "
f"another array must be 1D but '{idx_expr.name}' "
f"used to index into '{self.name}' has "
f"{len(dtype.shape)} dimensions.")
shape.append(_num_elements(dtype.shape[0]))
elif isinstance(idx_expr, (Call, Operation, CodeBlock)):
# We can't yet straightforwardly query the type of a function
# call or Operation - TODO #1799.
# pylint: disable=import-outside-toplevel
from psyclone.psyir.backend.fortran import FortranWriter
# TODO #1887 - get type of writer to use from Config object?
fvisitor = FortranWriter()
raise NotImplementedError(
f"The array index expressions for access "
f"'{fvisitor(self)}' include a function call or "
f"expression. Querying the return type of "
f"such things is yet to be implemented.")

return shape

def get_outer_range_index(self):
''' Return the index of the child that represents the outermost
array dimension with a Range construct.
Expand Down
10 changes: 4 additions & 6 deletions src/psyclone/psyir/nodes/array_of_structures_reference.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# -----------------------------------------------------------------------------
# BSD 3-Clause License
#
# Copyright (c) 2020-2021, Science and Technology Facilities Council.
# Copyright (c) 2020-2022, Science and Technology Facilities Council.
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -37,13 +37,11 @@
''' This module contains the implementation of the ArrayOfStructuresReference
node. '''

from __future__ import absolute_import

# Circular import if only '...nodes' is used:
from psyclone.psyir.nodes.structure_reference import StructureReference
from psyclone.psyir import symbols
from psyclone.psyir.nodes.array_of_structures_mixin import \
ArrayOfStructuresMixin
from psyclone.psyir.nodes.array_of_structures_mixin import (
ArrayOfStructuresMixin)
from psyclone.psyir.nodes.structure_reference import StructureReference


class ArrayOfStructuresReference(ArrayOfStructuresMixin, StructureReference):
Expand Down
21 changes: 18 additions & 3 deletions src/psyclone/psyir/nodes/array_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@

''' This module contains the implementation of the ArrayReference node. '''

from __future__ import absolute_import
from psyclone.psyir.nodes.array_mixin import ArrayMixin
from psyclone.psyir.nodes.reference import Reference
from psyclone.psyir.symbols import DataSymbol, DeferredType, UnknownType
from psyclone.psyir.symbols import (DataSymbol, DeferredType, UnknownType,
ScalarType, ArrayType)
from psyclone.errors import GenerationError


Expand Down Expand Up @@ -100,11 +100,26 @@ def create(symbol, indices):
return array

def __str__(self):
result = super(ArrayReference, self).__str__() + "\n"
result = super().__str__() + "\n"
for entity in self._children:
result += str(entity) + "\n"
return result

@property
def datatype(self):
'''
:returns: the datatype of the accessed array element(s).
:rtype: :py:class:`psyclone.psyir.symbols.DataType`
'''
shape = self._get_effective_shape()
if shape:
return ArrayType(self.symbol.datatype, shape)
# TODO #1857: Really we should just be able to return
# self.symbol.datatype here but currently arrays of scalars are
# handled in a different way to all other types of array.
return ScalarType(self.symbol.datatype.intrinsic,
self.symbol.datatype.precision)


# For AutoAPI documentation generation
__all__ = ['ArrayReference']
Loading

0 comments on commit e6e3842

Please sign in to comment.