Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/psyclone/domain/common/psylayer/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,6 @@

'''A package module for psyclone.domain.common.psylayer'''

from psyclone.domain.common.psylayer.global_reduction import GlobalReduction
from psyclone.domain.common.psylayer.psyloop import PSyLoop

__all__ = ["PSyLoop"]
76 changes: 76 additions & 0 deletions src/psyclone/domain/common/psylayer/global_reduction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import copy

from psyclone.configuration import Config
from psyclone.core import AccessType
from psyclone.errors import GenerationError, InternalError
from psyclone.psyGen import KernelArgument
from psyclone.psyir.nodes import Statement
from psyclone.psyir.nodes.node import Node


class GlobalReduction(Statement):
'''
Represents a global-reduction in the PSyIR.

:raises GenerationError: if distributed memory is not enabled.
:raises InternalError: if the supplied argument doesn't represent a scalar.

'''
# TODO is this really a leaf - it could have operands as children?
#: Textual description of the node.
_children_valid_format = "<LeafNode>"
_text_name = "GlobalReduction"
#: The colour to use when creating a view of this node.
_colour = "cyan"

def __init__(self, scalar: KernelArgument, parent: Node = None):
super().__init__(children=[], parent=parent)
# Check that distributed memory is enabled
if not Config.get().distributed_memory:
raise GenerationError(
f"It makes no sense to create a {self._text_name} object "
f"when distributed memory is not enabled (dm=False).")

# Check that the global sum argument is indeed a scalar
if not scalar.is_scalar:
raise InternalError(
f"{self._text_name}.init(): A global reduction argument should"
f" be a scalar but found argument of type "
f"'{scalar.argument_type}'.")

self._scalar = copy.copy(scalar)
if scalar:
# Update scalar values appropriately
# Here "readwrite" denotes how the class GlobalSum
# accesses/updates a scalar
self._scalar.access = AccessType.READWRITE
self._scalar.call = self

def node_str(self, colour: bool = True) -> str:
'''
Returns a text description of this node with (optional) control codes
to generate coloured output in a terminal that supports it.

:param colour: whether or not to include colour control codes.

:returns: description of this node, possibly coloured.
'''
return f"{self.coloured_name(colour)}[scalar='{self._scalar.name}']"

@property
def scalar(self):
''' Return the scalar field that this global reduction acts on '''
return self._scalar

@property
def dag_name(self) -> str:
'''
:returns: the name to use in the DAG for this node.
'''
return f"{self._text_name}({self._scalar.name})_{self.position}"

@property
def args(self):
''' Return the list of arguments associated with this node. Override
the base method and simply return our argument.'''
return [self._scalar]
10 changes: 10 additions & 0 deletions src/psyclone/domain/common/psylayer/global_sum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

from psyclone.domain.common.psylayer.global_reduction import GlobalReduction


class GlobalSum(GlobalReduction):
'''
Generic GlobalSum class which can be added to a Schedule.

'''
_text_name = "GlobalSum"
34 changes: 3 additions & 31 deletions src/psyclone/domain/lfric/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@
from psyclone.domain.lfric.lfric_kern_call_factory import LFRicKernCallFactory
from psyclone.domain.lfric.lfric_collection import LFRicCollection
from psyclone.domain.lfric.lfric_fields import LFRicFields
from psyclone.domain.lfric.lfric_global_max import LFRicGlobalMax
from psyclone.domain.lfric.lfric_global_min import LFRicGlobalMin
from psyclone.domain.lfric.lfric_global_sum import LFRicGlobalSum
from psyclone.domain.lfric.lfric_run_time_checks import LFRicRunTimeChecks
from psyclone.domain.lfric.lfric_invokes import LFRicInvokes
from psyclone.domain.lfric.lfric_scalar_args import LFRicScalarArgs
Expand All @@ -78,34 +81,3 @@
from psyclone.domain.lfric.lfric_invoke_schedule import LFRicInvokeSchedule
from psyclone.domain.lfric.lfric_dofmaps import LFRicDofmaps
from psyclone.domain.lfric.lfric_stencils import LFRicStencils


__all__ = [
'ArgOrdering',
'FunctionSpace',
'KernCallAccArgList',
'KernCallArgList',
'KernelInterface',
'KernStubArgList',
'LFRicArgDescriptor',
'LFRicCellIterators',
'LFRicCollection',
'LFRicConstants',
'LFRicDofmaps',
'LFRicDriverCreator',
'LFRicFields',
'LFRicHaloDepths',
'LFRicInvoke',
'LFRicInvokes',
'LFRicInvokeSchedule',
'LFRicKern',
'LFRicKernCallFactory',
'LFRicKernMetadata',
'LFRicLoop',
'LFRicLoopBounds',
'LFRicPSy',
'LFRicRunTimeChecks',
'LFRicScalarArgs',
'LFRicScalarArrayArgs',
'LFRicStencils',
'LFRicSymbolTable']
72 changes: 72 additions & 0 deletions src/psyclone/domain/lfric/lfric_global_max.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
from psyclone.domain.common.psylayer import GlobalReduction
from psyclone.errors import GenerationError
from psyclone.lfric import LFRicKernelArgument
from psyclone.psyGen import InvokeSchedule
from psyclone.psyir.nodes import (
Assignment, Call, Reference, StructureReference)
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.symbols import (
ContainerSymbol, DataSymbol, DataTypeSymbol, ImportInterface,
UnresolvedType)


class LFRicGlobalMax(GlobalReduction):
'''
LFRic specific global max class which can be added to and
manipulated in a schedule.

:param scalar: the kernel argument for which to perform a global min.
:param parent: the parent node of this node in the PSyIR.

:raises InternalError: if the supplied argument is not a scalar.
:raises GenerationError: if the scalar is not of "real" intrinsic type.

'''
_text_name = "LFRicGlobalMax"

def __init__(self, scalar: LFRicKernelArgument, parent: Node = None):
# Initialise the parent class
super().__init__(scalar, parent=parent)

# Check scalar intrinsic types that this class supports (only
# "real" for now)
if scalar.intrinsic_type != "real":
raise GenerationError(
f"LFRicGlobalMax currently only supports real scalars, but "
f"argument '{scalar.name}' in Kernel '{scalar.call.name}' has "
f"'{scalar.intrinsic_type}' intrinsic type.")

def lower_to_language_level(self) -> Node:
'''
:returns: this node lowered to language-level PSyIR.

'''
# Get the name strings to use
name = self._scalar.name
type_name = self._scalar.data_type
mod_name = self._scalar.module_name

# Get the symbols from the given names
symtab = self.ancestor(InvokeSchedule).symbol_table
sum_mod = symtab.find_or_create(mod_name, symbol_type=ContainerSymbol)
sum_type = symtab.find_or_create(type_name,
symbol_type=DataTypeSymbol,
datatype=UnresolvedType(),
interface=ImportInterface(sum_mod))
sum_name = symtab.find_or_create_tag("global_max",
symbol_type=DataSymbol,
datatype=sum_type)
tmp_var = symtab.lookup(name)

# Create the assignments
assign1 = Assignment.create(
lhs=StructureReference.create(sum_name, ["value"]),
rhs=Reference(tmp_var)
)
assign1.preceding_comment = "Perform global max"
self.parent.addchild(assign1, self.position)
assign2 = Assignment.create(
lhs=Reference(tmp_var),
rhs=Call.create(StructureReference.create(sum_name, ["get_max"]))
)
return self.replace_with(assign2)
77 changes: 77 additions & 0 deletions src/psyclone/domain/lfric/lfric_global_min.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
from psyclone.domain.common.psylayer import GlobalReduction
from psyclone.lfric import LFRicKernelArgument
from psyclone.errors import GenerationError
from psyclone.psyGen import InvokeSchedule
from psyclone.psyir.nodes import (
Assignment, Call, Node, Reference, StructureReference)
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.symbols import (
ContainerSymbol, DataSymbol, DataTypeSymbol, ImportInterface,
UnresolvedType)


class LFRicGlobalMin(GlobalReduction):
'''
LFRic specific global min class which can be added to and
manipulated in a schedule.

:param scalar: the kernel argument for which to perform a global min.
:param parent: the parent node of this node in the PSyIR.

:raises GenerationError: if the scalar is not of "real" or "integer"
intrinsic type.

'''
_text_name = "LFRicGlobalMin"

def __init__(self, scalar: LFRicKernelArgument, parent: Node = None):
# Initialise the parent class
super().__init__(scalar, parent=parent)

# Check scalar intrinsic types that this class supports (only
# "real" for now)
if scalar.intrinsic_type not in ["real", "integer"]:
raise GenerationError(
f"LFRicGlobalMin currently only supports real or integer "
f"scalars, but argument '{scalar.name}' in Kernel "
f"'{scalar.call.name}' has "
f"'{scalar.intrinsic_type}' intrinsic type.")

def lower_to_language_level(self) -> Node:
'''
:returns: this node lowered to language-level PSyIR.
'''

# Get the name strings to use
name = self._scalar.name
type_name = self._scalar.data_type
mod_name = self._scalar.module_name

# Get the symbols from the given names
symtab = self.ancestor(InvokeSchedule).symbol_table
# The Container from which to import the scalar type.
sum_mod = symtab.find_or_create(mod_name, symbol_type=ContainerSymbol)
# The scalar type.
scal_type = symtab.find_or_create(type_name,
symbol_type=DataTypeSymbol,
datatype=UnresolvedType(),
interface=ImportInterface(sum_mod))
# An instance of scalar type that we will use to get the global min.
sum_name = symtab.find_or_create_tag("global_min",
symbol_type=DataSymbol,
datatype=scal_type)
tmp_var = symtab.lookup(name)

# Assign the value of the local scalar to the new scalar_type quantity
assign1 = Assignment.create(
lhs=StructureReference.create(sum_name, ["value"]),
rhs=Reference(tmp_var)
)
assign1.preceding_comment = "Obtain global min"
self.parent.addchild(assign1, self.position)
# Use the 'get_min' method to compute the global min.
assign2 = Assignment.create(
lhs=Reference(tmp_var),
rhs=Call.create(StructureReference.create(sum_name, ["get_min"]))
)
return self.replace_with(assign2)
70 changes: 70 additions & 0 deletions src/psyclone/domain/lfric/lfric_global_sum.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from psyclone.domain.common.psylayer.global_sum import GlobalReduction
from psyclone.errors import GenerationError
from psyclone.lfric import LFRicKernelArgument
from psyclone.psyGen import InvokeSchedule
from psyclone.psyir.nodes import (
Assignment, Call, Reference, StructureReference)
from psyclone.psyir.nodes.node import Node
from psyclone.psyir.symbols import (
ContainerSymbol, DataSymbol, DataTypeSymbol, ImportInterface,
UnresolvedType)


class LFRicGlobalSum(GlobalReduction):
'''
LFRic specific global sum class which can be added to and
manipulated in a schedule.

:param scalar: the kernel argument for which to perform a global sum.
:param parent: the parent node of this node in the PSyIR.

:raises GenerationError: if the scalar is not of "real" intrinsic type.

'''
_text_name = "LFRicGlobalSum"

def __init__(self, scalar: LFRicKernelArgument, parent: Node = None):
# Initialise the parent class
super().__init__(scalar, parent=parent)
# Check scalar intrinsic types that this class supports (only
# "real" for now)
if scalar.intrinsic_type != "real":
raise GenerationError(
f"LFRicGlobalSum currently only supports real scalars, but "
f"argument '{scalar.name}' in Kernel '{scalar.call.name}' has "
f"'{scalar.intrinsic_type}' intrinsic type.")

def lower_to_language_level(self) -> Node:
'''
:returns: this node lowered to language-level PSyIR.
'''

# Get the name strings to use
name = self._scalar.name
type_name = self._scalar.data_type
mod_name = self._scalar.module_name

# Get the symbols from the given names
symtab = self.ancestor(InvokeSchedule).symbol_table
sum_mod = symtab.find_or_create(mod_name, symbol_type=ContainerSymbol)
sum_type = symtab.find_or_create(type_name,
symbol_type=DataTypeSymbol,
datatype=UnresolvedType(),
interface=ImportInterface(sum_mod))
sum_name = symtab.find_or_create_tag("global_sum",
symbol_type=DataSymbol,
datatype=sum_type)
tmp_var = symtab.lookup(name)

# Create the assignments
assign1 = Assignment.create(
lhs=StructureReference.create(sum_name, ["value"]),
rhs=Reference(tmp_var)
)
assign1.preceding_comment = "Perform global sum"
self.parent.addchild(assign1, self.position)
assign2 = Assignment.create(
lhs=Reference(tmp_var),
rhs=Call.create(StructureReference.create(sum_name, ["get_sum"]))
)
return self.replace_with(assign2)
Loading