Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def contains_unsupported_sum(fpnode):
'''
Examines the fparser2 parse tree represented by fpnode and returns True
if it contains a use of the SUM intrinisc with a 'dim' argument. (If
such a construct is included in a KERNELS region then the code produced
by v. 18.10 of the PGI compiler seg. faults.)
:returns: True if SUM(array(:,:), dim=blah) is found, False otherwise.
:rtype: bool
'''
from fparser.two.utils import walk_ast
from fparser.two import Fortran2003
intrinsics = walk_ast([fpnode], [Fortran2003.Intrinsic_Function_Reference])
for intrinsic in intrinsics:
if str(intrinsic.items[0]).lower() == "sum":
# If there's only one argument then we'll just have a Name
# and not an Actual_Arg_Spec_List (in which case we don't need to
# check for the 'dim' argument).
if isinstance(intrinsic.items[1],
Fortran2003.Actual_Arg_Spec_List):
# items[1] contains the Actual_Arg_Spec_List
actual_args = walk_ast(intrinsic.items[1].items,
[Fortran2003.Actual_Arg_Spec])
for arg in actual_args:
if str(arg.items[0]).lower() == "dim":
return True
return False
except KeyError:
# profile name is not supplied
pass
# pylint: enable=too-many-boolean-expressions
# The checks below are only for the NEMO API and can be removed
# once #435 is done.
invoke = nodes[0].root.invoke
if not isinstance(invoke, NemoInvoke):
return
# Get the parse tree of the routine containing this region
# pylint: disable=protected-access
ptree = invoke._ast
# pylint: enable=protected-access
# Search for the Specification_Part
if not walk_ast([ptree], [Fortran2003.Specification_Part]):
raise TransformationError(
"For the NEMO API, profiling can only be added to routines "
"which contain existing variable declarations (i.e. a "
"Specification Part) but '{0}' does not have any.".format(
invoke.name))
if not names:
raise InternalError("Unsupported assignment statement: '{0}'".
format(str(assign)))
if str(names[0]) == name:
# This is the variable declaration we're looking for
if not isinstance(assign.items[2],
Fortran2003.Array_Constructor):
from psyclone.parse import ParseError
raise ParseError(
"get_integer_array: RHS of assignment is not "
"an array constructor: '{0}'".format(str(assign)))
# fparser2 AST for Array_Constructor is:
# Array_Constructor('[', Ac_Value_List(',', (Name('w0'),
# Name('w1'))), ']')
# Construct a list of the names in the array constructor
names = walk_ast(assign.items[2].items, [Fortran2003.Name])
if not names:
raise InternalError("Failed to parse array constructor: "
"'{0}'".format(str(assign.items[2])))
return [str(name) for name in names]
return []
'''
Checks the supplied fparser2 parse tree for calls to the RESHAPE intrinsic.
The PGI compiler v.19.4 refuses to compile code that has such calls within
a KERNELS region. We have to check the parse tree to allow for the use
of RESHAPE within implicit loops which are not yet fully represented in
the PSyIR.
:param fpnode: fparser2 parse tree of code to check.
:type fpnode: :py:class:`fparser.two.Fortran2003.xxx`
:returns: True if the code fragment contains a RESHAPE call.
:rtype: bool
'''
from fparser.two.utils import walk_ast
from fparser.two import Fortran2003
intrinsics = walk_ast([fpnode], [Fortran2003.Intrinsic_Function_Reference])
for intrinsic in intrinsics:
if str(intrinsic.items[0]).lower() == "reshape":
return True
return False
for node in node_list[:]:
if isinstance(node, Fortran2003.Use_Stmt) and \
self.fortran_module == str(node.items[2]).lower():
# Check that the use statement matches the one we would
# insert (i.e. the code doesn't already contain a module
# with the same name as that used by the profiling API)
if str(node).lower() != self.use_stmt.lower():
raise NotImplementedError(
"Cannot add profiling to '{0}' because it already "
"'uses' a module named '{1}'".format(
routine_name, self.fortran_module))
found = True
# To make our check on name clashes below easier, remove
# the Name nodes associated with this use from our
# list of nodes.
names = walk_ast([node], [Fortran2003.Name])
for name in names:
node_list.remove(name)
if not found:
# We don't already have a use for the profiling module so
# add one.
reader = FortranStringReader(
"use profile_mod, only: ProfileData, ProfileStart, ProfileEnd")
# Tell the reader that the source is free format
reader.set_format(FortranFormat(True, False))
use = Fortran2003.Use_Stmt(reader)
spec_part.content.insert(0, use)
# Check that we won't have any name-clashes when we insert the
# symbols required for profiling. This check uses the list of symbols
# that we created before adding the `use profile_mod...` statement.
return False
else:
# Need to check for RESHAPE inside implicit loop
if contains_reshape(enode.ast):
log_msg(routine_name,
"Implicit loop contains RESHAPE call", enode)
return False
# Check for derived types. Should not have to do this as
# derived-types should end up in CodeBlocks
# but this does not happen for implicit loops.
if walk_ast([node.ast], [Fortran2003.Data_Ref]):
log_msg(routine_name, "Contains derived type", node)
return False
# Check for Function calls. Again, we should not have to do this
# but currently Implicit Loops are leaves in the PSyIR.
refs = walk_ast([node.ast], [Fortran2003.Part_Ref])
for ref in refs:
array_name = str(ref.items[0])
if array_name in NEMO_FUNCTIONS:
log_msg(routine_name,
"Implicit loop contains call to function '{0}'".
format(array_name), node)
return False
elif isinstance(enode, NemoLoop) and \
not isinstance(enode, NemoImplicitLoop):
# Heuristic:
# We don't want to put loops around 3D loops into KERNELS regions
# and nor do we want to put loops over levels into KERNELS regions
# if they themselves contain several 2D loops.
# In general, this heuristic will depend upon how many levels the
# model configuration will contain.
:rtype: bool
'''
from psyclone.psyGen import CodeBlock, IfBlock
from fparser.two.utils import walk_ast
from fparser.two import Fortran2003
# PGI (18.10) often produces code that fails at run time if a Kernels
# region includes If constructs.
excluded_node_types = (CodeBlock, IfBlock)
if node.walk(excluded_node_types):
return False
# Check that there are no derived-type references in the sub-tree (because
# PGI deep-copy doesn't like them).
# TODO #365 - this check should be part of our identification of valid
# NEMO kernels.
if walk_ast([node.ast], [Fortran2003.Data_Ref]):
return False
return True
def gen(self):
'''Return modified algorithm code.
:returns: The modified algorithm specification as an fparser2 \
parse tree.
:rtype: :py:class:`fparser.two.utils.Base`
'''
from fparser.two.utils import walk_ast
# pylint: disable=no-name-in-module
from fparser.two.Fortran2003 import Call_Stmt, Section_Subscript_List
idx = 0
# Walk through all statements looking for procedure calls
for statement in walk_ast(self._ast.content, [Call_Stmt]):
# found a Fortran call statement
call_name = str(statement.items[0])
if call_name.lower() == self._invoke_name.lower():
# The call statement is an invoke
# Get the PSy callee name and argument list and
# replace the existing algorithm invoke call with
# these.
psy_invoke_info = self._psy.invokes.invoke_list[idx]
new_name = psy_invoke_info.name
new_args = Section_Subscript_List(
", ".join(psy_invoke_info.alg_unique_args))
statement.items = (new_name, new_args)
# The PSy-layer generates a subroutine within a module
# so we need to add a 'use module_name, only :