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
2 changes: 1 addition & 1 deletion examples/lfric/scripts/KGOs/lfric_psyclone.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# Settings common to all APIs
[DEFAULT]
DISTRIBUTED_MEMORY = true
REPRODUCIBLE_REDUCTIONS = false
REPRODUCIBLE_REDUCTIONS = true
# Amount to pad the local summation array when REPRODUCIBLE_REDUCTIONS is true
REPROD_PAD_SIZE = 8
PSYIR_ROOT_NAME = psyir_tmp
Expand Down
2 changes: 1 addition & 1 deletion examples/lfric/scripts/KGOs/lfric_psyclone_no_annexed.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
# Settings common to all APIs
[DEFAULT]
DISTRIBUTED_MEMORY = true
REPRODUCIBLE_REDUCTIONS = false
REPRODUCIBLE_REDUCTIONS = true
# Amount to pad the local summation array when REPRODUCIBLE_REDUCTIONS is true
REPROD_PAD_SIZE = 8
PSYIR_ROOT_NAME = psyir_tmp
Expand Down
78 changes: 71 additions & 7 deletions src/psyclone/psyGen.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,6 +967,69 @@ def initialise_reduction_variable(self) -> None:
insert_loc.addchild(assign, cursor)
return new_node

def temp_to_array_assignment(self,
parent: Node,
table: SymbolTable) -> None:
'''
Generate the appropriate code to transfer the private reduction
temporary into the shared array for reproducible reductions.
The assignment is always placed as the final child of parent.

This method is designed to be used *after* a Kern has been lowered
(and thus detached) and therefore does not use `self.scope`.

:param parent: the node to which to add the assignment as a child.
:param table: the SymbolTable to use.
'''
tag = f"{self.name}:{self._reduction_arg.name}:local"
array_symbol = table.lookup_with_tag(tag)
local_var = table.lookup_with_tag(
f"{self.name}:{self._reduction_arg.name}:templocal")
thread_idx = table.lookup_with_tag("omp_thread_index")
arr_ref = ArrayReference.create(
array_symbol, [
Literal("1", ScalarType.integer_type()),
Reference(thread_idx)
])

assign = Assignment.create(
arr_ref, Reference(local_var)
)

assign.preceding_comment = (
"Store the thread private value of the reduction into the "
"shared array as required for reproducible reductions."
)

# Where to put it?
parent.addchild(assign)

def initialise_and_privatise_scalar_store(
self, parallel_region: Node, position: int, table: SymbolTable
) -> None:
'''
Generate the appropriate code to initialise the scalar reduction
variable inside the parallel region, and add it to the private clause.

:param parent: the parallel region to which to add the initialisation
as a child.
:param position: where in the parent's list of children to add
the new Loop.
:param table: the SymbolTable to use.
'''
local_var = table.lookup_with_tag(
f"{self.name}:{self._reduction_arg.name}:templocal")
assign = Assignment.create(Reference(local_var),
Literal("0", local_var.datatype))
parallel_region.dir_body.addchild(assign, position)
assign.preceding_comment = (
"Initialise thread-private reduction variable"
)
# The local var also needs to be thread private.
parallel_region.private_clause.addchild(
Reference(local_var)
)

def reduction_sum_loop(self,
parent: Node,
position: int,
Expand Down Expand Up @@ -1020,7 +1083,7 @@ def _reduction_reference(self):
Return the reference to the reduction variable if OpenMP is set to
be unreproducible, as we will be using the OpenMP reduction clause.
Otherwise we will be computing the reduction ourselves and therefore
need to store values into a (padded) array separately for each
need to store values into a temporary variable for each
thread.

:returns: reference to the variable to be reduced.
Expand All @@ -1031,12 +1094,8 @@ def _reduction_reference(self):
symtab = self.ancestor(InvokeSchedule).symbol_table
if self.reprod_reduction:
local_var = symtab.lookup_with_tag(
f"{self.name}:{self._reduction_arg.name}:local")
# Return a multi-valued ArrayReference for a reproducible reduction
array_dim = [
Literal("1", ScalarType.integer_type()),
Reference(symtab.lookup_with_tag("omp_thread_index"))]
return ArrayReference.create(local_var, array_dim)
f"{self.name}:{self._reduction_arg.name}:templocal")
return Reference(local_var)
# Return a single-valued Reference for a non-reproducible reduction
local_var = symtab.lookup_with_tag(
f"AlgArgs_{self._reduction_arg.text}")
Expand Down Expand Up @@ -1104,6 +1163,11 @@ def lower_to_language_level(self):

array_type = ArrayType(arg_sym.datatype,
2*[ArrayType.Extent.DEFERRED])
# Create a scalar temp to store to in the loop.
_ = table.find_or_create_tag(
root_name=f"local_temp_{self._reduction_arg.name}",
tag=f"{self.name}:{self._reduction_arg.name}:templocal",
symbol_type=DataSymbol, datatype=arg_sym.datatype)
local_var = table.find_or_create_tag(
root_name="local_"+self._reduction_arg.name,
tag=f"{self.name}:{self._reduction_arg.name}:local",
Expand Down
14 changes: 12 additions & 2 deletions src/psyclone/psyir/nodes/omp_directives.py
Original file line number Diff line number Diff line change
Expand Up @@ -1401,6 +1401,15 @@ def lower_to_language_level(self) -> Node:
self._add_reduction_clauses()

for call in reversed(reprod_red_call_list):
# Get the reduction variable to initialise and privatise.
tag = f"{call.name}:{call._reduction_arg.name}:templocal"
sym = self.scope.symbol_table.lookup_with_tag(tag)
call.initialise_and_privatise_scalar_store(
self, 0, self.scope.symbol_table
)
call.temp_to_array_assignment(
self.dir_body, self.scope.symbol_table
)
call.reduction_sum_loop(self.parent, self.position,
self.scope.symbol_table)

Expand Down Expand Up @@ -1916,8 +1925,9 @@ def lower_to_language_level(self):
# We only attempt to *automatically* add reduction clauses if we have a
# high-level (DSL) reduction operation.
reductions = self.reductions()
if not reductions:
# No high-level reduction operations.
if not reductions or self.reprod:
# No high-level reduction operations, or
# using reproducible reductions
return super().lower_to_language_level()

self.children[0].lower_to_language_level()
Expand Down
Loading
Loading