Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
parent.add(if_first)
if_first.add(AssignGen(if_first, lhs="first_time", rhs=".false."))
if_first.add(CommentGen(if_first,
" Ensure OpenCL run-time is initialised "
"for this PSy-layer module"))
if_first.add(CallGen(if_first, "psy_init"))
if_first.add(AssignGen(if_first, lhs="num_cmd_queues",
rhs="get_num_cmd_queues()"))
if_first.add(AssignGen(if_first, lhs="cmd_queues", pointer=True,
rhs="get_cmd_queues()"))
# Kernel pointers
kernels = self.walk(self._children, Call)
for kern in kernels:
kernel = "kernel_" + kern.name # TODO use namespace manager
parent.add(
DeclGen(parent, datatype="integer", kind="c_intptr_t",
save=True, target=True, entity_decls=[kernel]))
if_first.add(
AssignGen(
if_first, lhs=kernel,
rhs='get_kernel_by_name("{0}")'.format(kern.name)))
for entity in self._children:
entity.gen_code(parent)
if self.opencl:
# Ensure we block at the end of the invoke to ensure all
# kernels have completed before we return.
# TODO can we lift this restriction?
# BUG this assumes only the first command queue is used
parent.add(CommentGen(parent,
" Block until all kernels have finished"))
entity_decls=[arg.name for arg in args]))
# Scalar real grid properties
args = [x for x in grid_prop_args
if x.is_scalar() and x.intrinsic_type == "real"]
if args:
sub.add(DeclGen(sub, datatype="real", intent="in", kind="go_wp",
target=True,
entity_decls=[arg.name for arg in args]))
# Scalar arguments
args = args_filter(self._arguments.args, arg_types=["scalar"],
is_literal=False)
for arg in args:
if arg.space.lower() == "go_r_scalar":
sub.add(DeclGen(
sub, datatype="REAL", intent="in", kind="go_wp",
target=True, entity_decls=[arg.name]))
else:
sub.add(DeclGen(sub, datatype="INTEGER", intent="in",
target=True, entity_decls=[arg.name]))
# Declare local variables
err_name = argsetter_st.new_symbol_name("ierr")
argsetter_st.add(DataSymbol(err_name, INTEGER_TYPE))
sub.add(DeclGen(sub, datatype="integer", entity_decls=[err_name]))
# Set kernel arguments
sub.add(CommentGen(
sub,
" Set the arguments for the {0} OpenCL Kernel".format(self.name)))
for index, arg in enumerate(self.arguments.args):
# add the subroutine argument declarations for real scalars which
# are not global symbols
real_decls = list(filter(lambda x: x not in global_names,
self.unique_args_rscalars))
if real_decls:
my_decl_rscalars = DeclGen(invoke_sub, datatype="REAL",
intent="inout", kind="go_wp",
entity_decls=real_decls)
invoke_sub.add(my_decl_rscalars)
# add the subroutine argument declarations for integer scalars
# which are not global symbols
int_decls = list(filter(lambda x: x not in global_names,
self.unique_args_iscalars))
if int_decls:
my_decl_iscalars = DeclGen(invoke_sub, datatype="INTEGER",
intent="inout",
entity_decls=int_decls)
invoke_sub.add(my_decl_iscalars)
if self._schedule.const_loop_bounds and self.unique_args_arrays:
# Look-up the loop bounds using the first field object in the
# list
api_config = Config.get().api_conf("gocean1.0")
xstop = api_config.grid_properties["go_grid_xstop"].fortran \
.format(self.unique_args_arrays[0])
ystop = api_config.grid_properties["go_grid_ystop"].fortran \
.format(self.unique_args_arrays[0])
position = invoke_sub.last_declaration()
invoke_sub.add(CommentGen(invoke_sub, ""),
position=["after", position])
call = CallGen(prog,
"{0}%ReadVariable(\"{1}\", {2})"
.format(psy_data, var_name, local_name))
prog.add(call)
elif is_input:
# Now must be input and output:
# First read the pre-variable (which also allocates it):
call = CallGen(prog,
"{0}%ReadVariable(\"{1}\", {2})"
.format(psy_data, var_name, local_name))
prog.add(call)
# Then declare the post variable, and and read its values
# (ReadVariable will also allocate it)
sym = Symbol(local_name+post_suffix)
sym_table.add(sym)
decl = DeclGen(prog, "real", [local_name+post_suffix],
dimension=":,:", kind="8", allocatable=True)
prog.add(decl)
call = CallGen(prog,
"{0}%ReadVariable(\"{1}{3}\", {2}{3})"
.format(psy_data, var_name, local_name,
post_suffix))
prog.add(call)
else:
# Now the variable is output only. We need to read the
# post variable in, and create and allocate a pre variable
# with the same size as the post
sym = Symbol(local_name+post_suffix)
sym_table.add(sym)
decl = DeclGen(prog, "real", [local_name+post_suffix],
dimension=":,:", kind="8", allocatable=True)
prog.add(decl)
def gen_code(self, parent):
''' Generates GOcean specific invocation code (the subroutine called
by the associated invoke call in the algorithm layer). This
consists of the PSy invocation subroutine and the declaration of
its arguments.'''
from psyclone.f2pygen import SubroutineGen, DeclGen, TypeDeclGen
# create the subroutine
invoke_sub = SubroutineGen(parent, name=self.name,
args=self.psy_unique_var_names)
parent.add(invoke_sub)
self.schedule.gen_code(invoke_sub)
# add the subroutine argument declarations for arrays
if len(self.unique_args_arrays) > 0:
my_decl_arrays = DeclGen(invoke_sub, datatype="REAL",
intent="inout", kind="go_wp",
entity_decls=self.unique_args_arrays,
dimension=":,:")
invoke_sub.add(my_decl_arrays)
# add the subroutine argument declarations for scalars
if len(self.unique_args_scalars) > 0:
my_decl_scalars = \
TypeDeclGen(invoke_sub,
datatype="scalar_field_type",
entity_decls=self.unique_args_scalars,
intent="inout")
invoke_sub.add(my_decl_scalars)
.fortran.format(arg.name)
else:
# grid properties do not have such an attribute (because
# they are just pointers) so we check whether the device
# pointer is NULL.
device_buff = "{0}%grid%{1}_device".format(grid_arg.name,
arg.name)
condition = device_buff + " == 0"
host_buff = "{0}%grid%{1}".format(grid_arg.name, arg.name)
# Name of variable to hold no. of bytes of storage required
nbytes = symtab.lookup_with_tag("opencl_bytes").name
# Variable to hold write event returned by OpenCL runtime
wevent = symtab.lookup_with_tag("opencl_wevent").name
ifthen = IfThenGen(parent, condition)
parent.add(ifthen)
parent.add(DeclGen(parent, datatype="integer", kind="c_size_t",
entity_decls=[nbytes]))
parent.add(DeclGen(parent, datatype="integer",
kind="c_intptr_t", target=True,
entity_decls=[wevent]))
api_config = Config.get().api_conf("gocean1.0")
props = api_config.grid_properties
num_x = props["go_grid_nx"].fortran.format(grid_arg.name)
num_y = props["go_grid_ny"].fortran.format(grid_arg.name)
# Use c_sizeof() on first element of array to be copied over in
# order to cope with the fact that some grid properties are
# integer.
size_expr = "int({0}*{1}, 8)*c_sizeof({2}(1,1))" \
.format(num_x, num_y, host_buff)
ifthen.add(AssignGen(ifthen, lhs=nbytes, rhs=size_expr))
ifthen.add(CommentGen(ifthen, " Create buffer on device"))
# Get the name of the list of command queues (set in
def gen_code(self, parent):
''' Generates dynamo version 0.1 specific psy code for a call to
the dynamo kernel instance. '''
from psyclone.f2pygen import CallGen, DeclGen, AssignGen, UseGen
# TODO: we simply choose the first field as the lookup for the moment
field_name = self.arguments.args[0].name
# add a dofmap lookup using first field.
# TODO: This needs to be generalised to work for multiple dofmaps
parent.add(CallGen(parent, field_name+"%vspace%get_cell_dofmap",
["cell", "map"]))
parent.add(DeclGen(parent, datatype="integer",
entity_decls=["cell"]))
parent.add(DeclGen(parent, datatype="integer", pointer=True,
entity_decls=["map(:)"]))
# create the argument list on the fly so we can also create
# appropriate variables and lookups
arglist = []
arglist.append("nlayers")
arglist.append("ndf")
arglist.append("map")
found_gauss_quad = False
gauss_quad_arg = None
for arg in self._arguments.args:
if arg.requires_basis:
basis_name = arg.function_space+"_basis_"+arg.name
# create the subroutine
invoke_sub = SubroutineGen(parent, name=self.name,
args=self.psy_unique_vars)
# add the subroutine argument declarations
my_typedecl = TypeDeclGen(invoke_sub, datatype="field_type",
entity_decls=self.psy_unique_vars,
intent="inout")
invoke_sub.add(my_typedecl)
# declare field-type, column topology and function-space types
column_topology_name = "topology"
my_typedecl = TypeDeclGen(invoke_sub, datatype="ColumnTopology",
entity_decls=[column_topology_name],
pointer=True)
invoke_sub.add(my_typedecl)
# declare any basic types required
my_decl = DeclGen(invoke_sub, datatype="integer",
entity_decls=["nlayers"])
invoke_sub.add(my_decl)
for (idx, dof) in enumerate(self._dofs):
call = self._dofs[dof][0]
arg = self._dofs[dof][1]
# declare a type select clause which is used to map from a base
# class to FunctionSpace_type
type_select = SelectionGen(invoke_sub,
expr=arg.name + "_space=>" + arg.name +
"%function_space", typeselect=True)
invoke_sub.add(type_select)
my_typedecl = TypeDeclGen(invoke_sub,
datatype="FunctionSpace_type",
entity_decls=[arg.name+"_space"],
def gen_code(self, parent):
if self.field_space == "every":
from psyclone.f2pygen import DeclGen
from psyclone.psyir.nodes import BinaryOperation
dim_var = DeclGen(parent, datatype="INTEGER",
entity_decls=[self.variable.name])
parent.add(dim_var)
# Update start loop bound
self.start_expr = Literal("1", INTEGER_TYPE, parent=self)
# Update stop loop bound
if self._loop_type == "inner":
index = "1"
elif self._loop_type == "outer":
index = "2"
self.stop_expr = BinaryOperation(BinaryOperation.Operator.SIZE,
parent=self)
self.stop_expr.addchild(
Reference(DataSymbol(self.field_name, INTEGER_TYPE),
parent=self.stop_expr))