Skip to content
Open
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
11 changes: 6 additions & 5 deletions doc/user_guide/psy_data.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,11 +262,12 @@ The syntax for a variable specification is one of:
``PSY_VALUE_RANGE="variable=..."``
The specified variable name is tested in any instrumented code region.

Note that you have to use the variable names used in the created psy-layer.
For example, in GOcean, the field ``f`` will become ``f%data`` and in LFRic
field ``f`` will become ``f_data``. You must make sure to specify the actual names,
otherwise your test will not be executed as expected. You can always just
look at the created psy-layer file to find the exact names.
Note that in LFRic you have to use the variable names used in the created
psy-layer - the field ``f`` will become ``f_data``. You must make sure to
specify the actual names, otherwise your test will not be executed as expected.
GOcean supports the usage of the original field names.
You can always just look at the created psy-layer file to find the exact names.


A value range is specified as a ``:`` separated tuple::

Expand Down
2 changes: 1 addition & 1 deletion examples/gocean/eg5/readonly/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ compile: transform $(NAME)

run: compile
./read_only_test 2>&1 | \
grep "2d Double array b_fld%data has been modified in main : update"
grep "2d Double array b_fld has been modified in main : update"

alg.f90 psy.f90: transform

Expand Down
2 changes: 1 addition & 1 deletion examples/gocean/eg5/readonly/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Allocating C-T field with bounds: (1: 12,1: 6)
Internal region is:(2: 4,2: 4)
Grid has bounds: (1: 12,1: 6)
------------------- PSyData -------------------
2d Double array b_fld%data has been modified in main : update
2d Double array b_fld has been modified in main : update
Original checksum: 4611686018427387904
New checksum: 4638355772470722560
------------------- PSyData -------------------
Expand Down
2 changes: 1 addition & 1 deletion examples/gocean/eg5/value_range_check/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ transform: test.x90 value_range_check_transformation.py

run: compile
# Note that if the output line is not found, the make will abort with error
./value_range_check 2>&1| grep "PSyData: Variable 'a_fld%data' has the invalid value"
./value_range_check 2>&1| grep "PSyData: Variable 'a_fld' has the invalid value"

$(NAME): $(INF_LIB) $(VALUE_RANGE_CHECK_DIR)/$(LIB_NAME) $(KERNELS) alg.o psy.o
$(F90) $(F90FLAGS) $(KERNELS) alg.o psy.o -o $(NAME) \
Expand Down
12 changes: 6 additions & 6 deletions examples/gocean/eg5/value_range_check/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ specify the value range for variables as outlined here:
https://psyclone.readthedocs.io/en/latest/user_guide/psy_data.html#value-range-check

```
$ PSY_VALUE_RANGE="main.init.b_fld%data=2:3" ./value_range_check
$ PSY_VALUE_RANGE="main.init.b_fld=2:3" ./value_range_check
...
Allocating C-T field with bounds: (1: 6,1: 6), internal region is (2: 4,2: 4)
PSyData: Variable 'b_fld%data' has the value 0.0000000000000000 at index/indices 6 1 in module 'main', region 'init', which is not between '2.0000000000000000' and '3.0000000000000000'.
PSyData: Variable 'b_fld' has the value 0.0000000000000000 at index/indices 6 1 in module 'main', region 'init', which is not between '2.0000000000000000' and '3.0000000000000000'.
...
PSyData: Variable 'a_fld%data' has the invalid value 'Inf' at index/indices 1 1 in module 'main', region 'update'.
PSyData: Variable 'a_fld' has the invalid value 'Inf' at index/indices 1 1 in module 'main', region 'update'.
...

```
Expand All @@ -48,11 +48,11 @@ the kernel computations.
Note that you do not need to specify a kernel name and module name if your variable
name is unique. You can remove the module and kernel name:
```
$ PSY_VALUE_RANGE="b_fld%data=2:3" ./value_range_check
$ PSY_VALUE_RANGE="b_fld=2:3" ./value_range_check

PSyData: Variable 'b_fld%data' has the value 0.0000000000000000 at index/indices 6 1 in module 'main' region 'init', which is not between '2.0000000000000000' and '3.0000000000000000'.
PSyData: Variable 'b_fld' has the value 0.0000000000000000 at index/indices 6 1 in module 'main' region 'init', which is not between '2.0000000000000000' and '3.0000000000000000'.
...
PSyData: Variable 'b_fld%data' has the value 0.0000000000000000 at index/indices 6 1 in module 'main' rqegion 'update', which is not between '2.0000000000000000' and '3.0000000000000000'.
PSyData: Variable 'b_fld' has the value 0.0000000000000000 at index/indices 6 1 in module 'main' rqegion 'update', which is not between '2.0000000000000000' and '3.0000000000000000'.
...
```
Now that the kernel and module names are not being specified, warnings are also printed
Expand Down
2 changes: 1 addition & 1 deletion examples/lfric/eg17/value_range_check/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ transform: main_psy.f90 main_alg.f90
compile: transform $(EXEC)

run: compile
@# Run application and grep fro the expected value range message:
@# Run application and grep for the expected value range message:
PSY_VALUE_RANGE="field1_data=0:7" ./$(EXEC) 2>&1 | grep "at index/indices"

$(EXEC): $(LFRIC_LIB) $(VALUE_RANGE_LIB) $(OBJ)
Expand Down
8 changes: 5 additions & 3 deletions src/psyclone/domain/common/driver_creator.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ def _create_read_in_code(
# doing lookups, external variables are handled below). Note that at
# the moment we consider all read and/or written as input variables.
read_stmts = []
for module_name, signature in read_write_info.all_used_vars_list:
for (module_name, signature,
_dsl_name) in read_write_info.all_used_vars_list:
if not module_name:
orig_sym = original_symtab.lookup(signature[0])
sym = orig_sym.copy()
Expand All @@ -287,7 +288,8 @@ def _create_read_in_code(
# so that they match the literal tags of the extracting psy-layer
ExtractNode.bring_external_symbols(read_write_info, symbol_table)
mod_man = ModuleManager.get()
for module_name, signature in read_write_info.all_used_vars_list:
for (module_name, signature,
_dsl_name) in read_write_info.all_used_vars_list:
# Only add if a variable is not supposed to be ignored
if module_name and (module_name, signature) not in vars_to_ignore:
mod_info = mod_man.get_module_info(module_name)
Expand All @@ -303,7 +305,7 @@ def _create_read_in_code(
# Finally handle the output variables (these are the ones compared
# to a stored _post variable)
output_symbols = []
for module_name, signature in read_write_info.write_list:
for module_name, signature, _dsl_name in read_write_info.write_list:
if (module_name, signature) in vars_to_ignore:
continue
# Find the right symbol for the variable. Note that all variables
Expand Down
8 changes: 6 additions & 2 deletions src/psyclone/gocean1p0.py
Original file line number Diff line number Diff line change
Expand Up @@ -1038,13 +1038,17 @@ def offset_expression(
depth = arg.stencil.depth(i, j)
for offset in range(1, depth+1):

# Generate data accessor accounting for offsets
# Generate data accessor accounting for offsets.
# Also add the field name (which is the symbol
# name) as 'dsl_name' for the reference, so PSyData
# can support user-friendly names.
access = StructureReference.create(symbol, [
("data", [
offset_expression(j, inner_symbol, offset),
offset_expression(i, outer_symbol, offset)
])
])
],
dsl_name=symbol.name)
if arg.access in (AccessType.WRITE,
AccessType.READWRITE):
write_accesses.append(access.copy())
Expand Down
5 changes: 3 additions & 2 deletions src/psyclone/psyir/nodes/extract_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ def determine_postfix(read_write_info: "ReadWriteInfo",
all_vars = read_write_info.all_used_vars_list
# The signatures in the input/output list need to be converted
# back to strings to easily append the suffix.
all_vars_string = [str(input_var) for _, input_var in all_vars]
all_vars_string = [str(input_var) for _, input_var, _ in all_vars]
while any(str(out_sig)+postfix+str(suffix) in all_vars_string
for out_sig in read_write_info.signatures_written):
suffix = cast(int, suffix)
Expand Down Expand Up @@ -429,7 +429,8 @@ def bring_external_symbols(read_write_info: "ReadWriteInfo",
# pylint: disable=import-outside-toplevel
from psyclone.parse import ModuleManager
mod_man = ModuleManager.get()
for module_name, signature in read_write_info.all_used_vars_list:
for (module_name, signature,
_dsl_name) in read_write_info.all_used_vars_list:
if not module_name:
# Ignore local symbols, which will have been added above
continue
Expand Down
22 changes: 12 additions & 10 deletions src/psyclone/psyir/nodes/psy_data_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -461,7 +461,9 @@ def _create_unique_names(self, var_list, symbol_table):

'''
out_list = []
for (module_name, signature) in var_list:
for (module_name, signature, dsl_name) in var_list:
if not dsl_name:
dsl_name = str(signature)
if module_name:
container = symbol_table.find_or_create(
module_name, symbol_type=ContainerSymbol)
Expand All @@ -475,7 +477,7 @@ def _create_unique_names(self, var_list, symbol_table):
else:
# This is a local variable anyway, no need to rename:
unique_sig = signature
out_list.append((module_name, signature, unique_sig))
out_list.append((module_name, signature, unique_sig, dsl_name))
return out_list

def _populate_region_name(self):
Expand Down Expand Up @@ -643,31 +645,31 @@ def gen_type_bound_call(typename, methodname, argument_list=None,
# values of a variable "A" as "A" in the pre-variable list,
# and store the modified value of "A" later as "A_post".
if has_var:
for module_name, sig, unique_sig in pre_variable_list:
for module_name, _sig, unique_sig, dsl_name in pre_variable_list:
if module_name:
module_name = f"@{module_name}"
call = gen_type_bound_call(
self._var_name, "PreDeclareVariable",
[f"\"{sig}{pre_suffix}{module_name}\"", unique_sig])
[f"\"{dsl_name}{pre_suffix}{module_name}\"", unique_sig])
self.parent.children.insert(self.position, call)

for module_name, sig, unique_sig in post_variable_list:
for module_name, _sig, unique_sig, dsl_name in post_variable_list:
if module_name:
module_name = f"@{module_name}"
call = gen_type_bound_call(
self._var_name, "PreDeclareVariable",
[f"\"{sig}{post_suffix}{module_name}\"", unique_sig])
[f"\"{dsl_name}{post_suffix}{module_name}\"", unique_sig])
self.parent.children.insert(self.position, call)

call = gen_type_bound_call(self._var_name, "PreEndDeclaration")
self.parent.children.insert(self.position, call)

for module_name, sig, unique_sig in pre_variable_list:
for module_name, _sig, unique_sig, dsl_name in pre_variable_list:
if module_name:
module_name = f"@{module_name}"
call = gen_type_bound_call(
self._var_name, "ProvideVariable",
[f"\"{sig}{pre_suffix}{module_name}\"", unique_sig])
[f"\"{dsl_name}{pre_suffix}{module_name}\"", unique_sig])
self.parent.children.insert(self.position, call)

call = gen_type_bound_call(self._var_name, "PreEnd")
Expand All @@ -686,12 +688,12 @@ def gen_type_bound_call(typename, methodname, argument_list=None,
# Only add PostStart() if there is at least one variable.
call = gen_type_bound_call(self._var_name, "PostStart")
self.parent.children.insert(self.position, call)
for module_name, sig, unique_sig in post_variable_list:
for module_name, _sig, unique_sig, dsl_name in post_variable_list:
if module_name:
module_name = f"@{module_name}"
call = gen_type_bound_call(
self._var_name, "ProvideVariable",
[f"\"{sig}{post_suffix}{module_name}\"", unique_sig])
[f"\"{dsl_name}{post_suffix}{module_name}\"", unique_sig])
self.parent.children.insert(self.position, call)

# PSyData end call
Expand Down
26 changes: 23 additions & 3 deletions src/psyclone/psyir/nodes/reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,26 @@ class Reference(DataNode):
Node representing a Reference Expression.

:param symbol: the symbol being referenced.
:type symbol: :py:class:`psyclone.psyir.symbols.Symbol`
:param dsl_name: an optional name indicating what the name of this
reference is on a DSL level. E.g. in GOcean, a StructureReference
to `field%data` would have the dsl name `field`. This is used by
some PSyData transformations to use user-friendly names (i.e.
independent of the automatic variable naming in the PSy layer).
:param kwargs: additional keyword arguments provided to the super class.
:type kwargs: unwrapped dict.

'''
# Textual description of the node.
_children_valid_format = "<LeafNode>"
_text_name = "Reference"
_colour = "yellow"

def __init__(self, symbol, **kwargs):
def __init__(self,
symbol: Symbol,
dsl_name: Optional[str] = None,
**kwargs: dict):
super().__init__(**kwargs)
self.symbol = symbol
self._dsl_name = dsl_name

def __eq__(self, other):
'''
Expand Down Expand Up @@ -157,6 +164,19 @@ def name(self):
'''
return self._symbol.name

@property
def dsl_name(self) -> Optional[str]:
"""
The name used for this reference on a DSL level. E.g., a
field reference `field_proxy` (which is an internal name
used in the PSy layer) would have the DSL name `field`.
This is used by some PSyData transformations to provide
user-friendly names.

:returns: the name used for this reference on a DSL level.
"""
return self._dsl_name

def node_str(self, colour=True):
''' Create a text description of this node in the schedule, optionally
including control codes for colour.
Expand Down
42 changes: 26 additions & 16 deletions src/psyclone/psyir/nodes/structure_reference.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,34 +61,34 @@ def _validate_child(position, child):
return False

@staticmethod
def create(symbol, members, parent=None, overwrite_datatype=None):
def create(symbol: DataSymbol,
members: list[Union[str, tuple[str, list[Node]]]],
parent: Optional[Node] = None,
overwrite_datatype: Optional[DataType] = None,
dsl_name: Optional[str] = None) -> StructureReference:
'''
Create a StructureReference instance given a symbol and a
list of components. e.g. for "field%bundle(2)%flag" this
list would be
[("bundle", [Literal("2", ScalarType.integer4_type())]), "flag"].

:param symbol: the symbol that this reference is to.
:type symbol: :py:class:`psyclone.psyir.symbols.DataSymbol`
:param members: the component(s) of the structure that make up \
the full access. Any components that are array accesses must \
provide the name of the array and a list of DataNodes describing \
:param members: the component(s) of the structure that make up
the full access. Any components that are array accesses must
provide the name of the array and a list of DataNodes describing
which part of it is accessed.
:type members: list of str or 2-tuples containing (str, \
list of nodes describing array access)
:param parent: the parent of this node in the PSyIR.
:type parent: sub-class of :py:class:`psyclone.psyir.nodes.Node`
:param overwrite_datatype: the datatype for the reference, which will \
overwrite the value determined by analysing the corresponding \
user defined type. This is useful when e.g. the module that \
:param overwrite_datatype: the datatype for the reference, which will
overwrite the value determined by analysing the corresponding
user defined type. This is useful when e.g. the module that
declares the structure cannot be accessed.
:type overwrite_datatype: \
Optional[:py:class:`psyclone.psyir.symbols.DataType`]
:param dsl_name: the name of a DSL field that this reference is
accessing (e.g. `field_proxy%data` might reference `field`)

:returns: a StructureReference instance.
:rtype: :py:class:`psyclone.psyir.nodes.StructureReference`

:raises TypeError: if the supplied symbol is not a DataSymbol.
:raises TypeError: if the supplied dsl_name is not a string.

'''
if not isinstance(symbol, DataSymbol):
Expand All @@ -102,9 +102,16 @@ def create(symbol, members, parent=None, overwrite_datatype=None):
f"StructureReference.create() should be a DataType but found "
f"'{type(symbol).__name__}'.")

if dsl_name and not isinstance(dsl_name, str):
raise TypeError(
f"The 'dsl_name' argument to StructureReference.create() "
f"should be a string, but found "
f"'{type(dsl_name).__name__}'.")

return StructureReference.\
_create(symbol, symbol.datatype, members, parent=parent,
overwrite_datatype=overwrite_datatype)
overwrite_datatype=overwrite_datatype,
dsl_name=dsl_name)

@classmethod
def _create(cls,
Expand All @@ -113,6 +120,7 @@ def _create(cls,
members: list[Union[str, Tuple[str, list[Node]]]],
parent: Optional[Node] = None,
overwrite_datatype: Optional[DataType] = None,
dsl_name: Optional[str] = None
) -> StructureReference:
# pylint: disable=too-many-arguments
'''
Expand All @@ -136,6 +144,8 @@ def _create(cls,
overwrite the value determined by analysing the corresponding
user defined type. This is useful when e.g. the module that
declares the structure cannot be accessed.
:param dsl_name: the name of a DSL field that this reference is
accessing (e.g. `field_proxy%data` might reference `field`)

:returns: a StructureReference instance.

Expand Down Expand Up @@ -175,7 +185,7 @@ def _create(cls,
f"symbol '{symbol.name}'")

# Create the base reference to the symbol that is a structure
ref = cls(symbol, parent=parent)
ref = cls(symbol, parent=parent, dsl_name=dsl_name)

# Bottom-up creation of full reference. The last element in the members
# list must be either an ArrayMember or a Member.
Expand Down
Loading
Loading