Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
:raises TransformationError: if the parent of the MATMUL \
operation is not an assignment.
:raises TransformationError: if the matmul arguments are not in \
the required form.
'''
# pylint: disable=too-many-branches
# Import here to avoid circular dependencies.
from psyclone.psyir.transformations import TransformationError
super(Matmul2CodeTrans, self).validate(node, options)
# Check the matmul is the only code on the rhs of an assignment
# i.e. ... = matmul(a,b)
if not isinstance(node.parent, Assignment):
raise TransformationError(
"Matmul2CodeTrans only supports the transformation of a "
"MATMUL operation when it is the sole operation on the rhs "
"of an assignment.")
matrix = node.children[0]
vector = node.children[1]
# The children of matvec should be References
if not (isinstance(matrix, Reference) and
isinstance(vector, Reference)):
raise TransformationError(
"Expected children of a MATMUL BinaryOperation to be "
"references, but found '{0}', '{1}'."
"".format(type(matrix).__name__,
type(vector).__name__))
def _assignment_handler(self, node, parent):
'''
Transforms an fparser2 Assignment_Stmt to the PSyIR representation.
:param node: node in fparser2 AST.
:type node: :py:class:`fparser.two.Fortran2003.Assignment_Stmt`
:param parent: Parent node of the PSyIR node we are constructing.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:returns: PSyIR representation of node.
:rtype: :py:class:`psyclone.psyir.nodes.Assignment`
'''
assignment = Assignment(node, parent=parent)
self.process_nodes(parent=assignment, nodes=[node.items[0]])
self.process_nodes(parent=assignment, nodes=[node.items[2]])
return assignment
elif not isinstance(extent, ArrayType.Extent) and \
allocatable:
# We have an allocatable array with a defined extent.
# This is invalid Fortran.
raise InternalError(
"Invalid Fortran: '{0}'. An array with defined "
"extent cannot have the ALLOCATABLE attribute.".
format(str(decl)))
if initialisation:
if has_constant_value:
# If it is a parameter parse its initialization into
# a dummy Assignment inside a Schedule which temporally
# hijacks the parent's node symbol table
tmp_sch = Schedule(symbol_table=parent.symbol_table)
dummynode = Assignment(parent=tmp_sch)
tmp_sch.addchild(dummynode)
expr = initialisation.items[1]
self.process_nodes(parent=dummynode, nodes=[expr])
ct_expr = dummynode.children[0]
else:
raise NotImplementedError(
"Could not process {0}. Initialisations on the"
" declaration statements are only supported for "
"parameter declarations.".format(decl.items))
if char_len is not None:
raise NotImplementedError(
"Could not process {0}. Character length "
"specifications are not supported."
"".format(decl.items))
# and recovers them, otherwise it raises an error as currently
# Statement Functions are not supported in PSyIR.
for stmtfn in walk(nodes, Fortran2003.Stmt_Function_Stmt):
(fn_name, arg_list, scalar_expr) = stmtfn.items
try:
symbol = parent.symbol_table.lookup(fn_name.string.lower())
if symbol.is_array:
# This is an array assignment wrongly categorized as a
# statement_function by fparser2.
array_name = fn_name
array_subscript = arg_list.items
assignment_rhs = scalar_expr
# Create assingment node
assignment = Assignment(parent=parent)
parent.addchild(assignment)
# Build lhs
lhs = Array(symbol, parent=assignment)
self.process_nodes(parent=lhs, nodes=array_subscript)
assignment.addchild(lhs)
# Build rhs
self.process_nodes(parent=assignment,
nodes=[assignment_rhs])
else:
raise InternalError(
"Could not process '{0}'. Symbol '{1}' is in the"
" SymbolTable but it is not an array as expected, so"
" it can not be recovered as an array assignment."
"".format(str(stmtfn), symbol.name))
def _array_syntax_to_indexed(self, parent, loop_vars):
'''
Utility function that modifies each Array object in the supplied PSyIR
fragment so that they are indexed using the supplied loop variables
rather than having colon array notation.
:param parent: root of PSyIR sub-tree to search for Array \
references to modify.
:type parent: :py:class:`psyclone.psyir.nodes.Node`
:param loop_vars: the variable names for the array indices.
:type loop_vars: list of str
:raises NotImplementedError: if array sections of differing ranks are \
found.
'''
assigns = parent.walk(Assignment)
# Check that the LHS of any assignment uses recognised array
# notation.
for assign in assigns:
_ = self._array_notation_rank(assign.lhs)
# TODO #717 if the supplied code accidentally omits array
# notation for an array reference on the RHS then we will
# identify it as a scalar and the code produced from the
# PSyIR (using e.g. the Fortran backend) will not
# compile. We need to implement robust identification of the
# types of all symbols in the PSyIR fragment.
arrays = parent.walk(Array)
first_rank = None
for array in arrays:
# Check that this is a supported array reference and that
# all arrays are of the same rank
rank = len([child for child in array.children if
:type symbol_table: :py:class:`psyclone.psyir.symbols.SymbolTable`
:param options: a dictionary with options for transformations.
:type options: dictionary of string:values or None
:returns: 2-tuple of new schedule and memento of transform.
:rtype: (:py:class:`psyclone.nemo.NemoInvokeSchedule`, \
:py:class:`psyclone.undoredo.Memento`)
'''
self.validate(node, symbol_table)
schedule = node.root
memento = Memento(schedule, self, [node, symbol_table])
oper_parent = node.parent
assignment = node.ancestor(Assignment)
# Create a temporary result variable. There is an assumption
# here that the MIN Operator returns a PSyIR real type. This
# might not be what is wanted (e.g. the args might PSyIR
# integers), or there may be errors (arguments are of
# different types) but this can't be checked as we don't have
# access to a symbol table (see #500) and don't have the
# appropriate methods to query nodes (see #658).
res_var = symbol_table.new_symbol_name("res_min")
res_var_symbol = DataSymbol(res_var, DataType.REAL)
symbol_table.add(res_var_symbol)
# Create a temporary variable. Again there is an
# assumption here about the datatype - please see previous
# comment (associated issues #500 and #658).
tmp_var = symbol_table.new_symbol_name("tmp_min")
tmp_var_symbol = DataSymbol(tmp_var, DataType.REAL)
# Array reference using a range
LBOUND = BinaryOperation.create(
BinaryOperation.Operator.LBOUND,
Reference(ARRAY), INT_ONE)
UBOUND = BinaryOperation.create(
BinaryOperation.Operator.UBOUND,
Reference(ARRAY), INT_ONE)
MY_RANGE = Range.create(LBOUND, UBOUND)
TMPARRAY = Array.create(ARRAY, [MY_RANGE])
# Assignments
ASSIGN1 = Assignment.create(TMP1, ZERO)
ASSIGN2 = Assignment.create(TMP2, ZERO)
ASSIGN3 = Assignment.create(TMP2, BINARYOPERATION)
ASSIGN4 = Assignment.create(TMP1, TMP2)
ASSIGN5 = Assignment.create(TMP1, NARYOPERATION)
ASSIGN6 = Assignment.create(TMPARRAY, TWO)
# If statement
IF_CONDITION = BinaryOperation.create(BinaryOperation.Operator.GT, TMP1, ZERO)
IFBLOCK = IfBlock.create(IF_CONDITION, [ASSIGN3, ASSIGN4])
# Loop
LOOP = Loop.create(INDEX_NAME, INT_ZERO, INT_ONE, INT_ONE, [IFBLOCK])
# KernelSchedule
KERNEL_SCHEDULE = KernelSchedule.create("work", SYMBOL_TABLE,
[ASSIGN2, LOOP, ASSIGN5, ASSIGN6])
# Container
CONTAINER_SYMBOL_TABLE = SymbolTable()
CONTAINER = Container.create("CONTAINER", CONTAINER_SYMBOL_TABLE,