Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
:param node: a BinaryOperation PSyIR node.
:type node: :py:class:`psyclone.psyir.nodes.BinaryOperation`
:returns: the SIR Python code.
:rtype: str
:raises VisitorError: if there is no mapping from the PSyIR \
operator to SIR.
'''
binary_operators = {
BinaryOperation.Operator.ADD: '+',
BinaryOperation.Operator.SUB: '-',
BinaryOperation.Operator.MUL: '*',
BinaryOperation.Operator.DIV: '/',
BinaryOperation.Operator.POW: '**',
BinaryOperation.Operator.EQ: '==',
BinaryOperation.Operator.NE: '!=',
BinaryOperation.Operator.LE: '<=',
BinaryOperation.Operator.LT: '<',
BinaryOperation.Operator.GE: '>=',
BinaryOperation.Operator.GT: '>',
BinaryOperation.Operator.AND: '&&',
BinaryOperation.Operator.OR: '||'}
self._depth += 1
lhs = self._visit(node.children[0])
try:
oper = binary_operators[node.operator]
except KeyError:
raise VisitorError(
self._iteration_space][self._loop_type]
stop = bounds["stop"].format(start='2', stop=stop)
# Remove all white spaces
stop = "".join(stop.split())
# This common case is a bit of compile-time computation
# but it helps to fix all of the test cases.
if stop == "2-1":
stop = "1"
return Literal(stop, INTEGER_TYPE, self)
if self.field_space == "go_every":
# Bounds are independent of the grid-offset convention in use
# We look-up the upper bounds by enquiring about the SIZE of
# the array itself
stop = BinaryOperation(BinaryOperation.Operator.SIZE,
self)
# TODO 363 - needs to be updated once the PSyIR has support for
# Fortran derived types.
api_config = Config.get().api_conf("gocean1.0")
# Use the data property to access the member of the field that
# contains the actual grid points. The property value is a
# string with a placeholder ({0}) where the name of the field
# must go.
data = api_config.grid_properties["go_grid_data"].fortran \
.format(self.field_name)
stop.addchild(Literal(data, INTEGER_TYPE, parent=stop))
if self._loop_type == "inner":
stop.addchild(Literal("1", INTEGER_TYPE, parent=stop))
elif self._loop_type == "outer":
stop.addchild(Literal("2", INTEGER_TYPE, parent=stop))
return stop
my_range = node.parent
array = my_range.parent
array_index = array.children.index(my_range) + 1
# pylint: disable=too-many-boolean-expressions
if isinstance(node, BinaryOperation) and \
node.operator == operator and \
isinstance(node.children[0], Reference) and \
node.children[0].name == array.name and \
isinstance(node.children[1], Literal) and \
node.children[1].datatype.intrinsic == \
ScalarType.Intrinsic.INTEGER and \
node.children[1].value == str(array_index):
return True
return False
if _full_extent(node.start, BinaryOperation.Operator.LBOUND):
# The range starts for the first element in this
# dimension. This is the default in Fortran so no need to
# output anything.
start = ""
else:
start = self._visit(node.start)
if _full_extent(node.stop, BinaryOperation.Operator.UBOUND):
# The range ends with the last element in this
# dimension. This is the default in Fortran so no need to
# output anything.
stop = ""
else:
stop = self._visit(node.stop)
result = "{0}:{1}".format(start, stop)
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))
self.stop_expr.addchild(Literal(index, INTEGER_TYPE,
parent=self.stop_expr))
else: # one of our spaces so use values provided by the infrastructure
# loop bounds
# TODO: Issue 440. Implement derive types in PSyIR
if self._loop_type == "inner":
self.start_expr = Reference(
self.field_space + "%istart", parent=self)
self.stop_expr = Reference(
self.field_space + "%istop", parent=self)
# A lower limit is specified
geop = BinaryOperation(BinaryOperation.Operator.GE,
parent=new_parent)
self.process_nodes(parent=geop, nodes=[selector])
self.process_nodes(parent=geop, nodes=[node.items[0]])
new_parent.addchild(geop)
if node.items[1]:
# An upper limit is specified
leop = BinaryOperation(BinaryOperation.Operator.LE,
parent=new_parent)
self.process_nodes(parent=leop, nodes=[selector])
self.process_nodes(parent=leop, nodes=[node.items[1]])
new_parent.addchild(leop)
else:
# The case value is some scalar initialisation expression
bop = BinaryOperation(BinaryOperation.Operator.EQ,
parent=parent)
parent.addchild(bop)
self.process_nodes(parent=bop, nodes=[selector])
self.process_nodes(parent=bop, nodes=[node])
def function_format(function_str, expr1, expr2):
'''
:param str function_str: Name of the function.
:param str expr1: String representation of the first operand.
:param str expr2: String representation of the second operand.
:returns: C language binary function expression.
:rtype: str
'''
return function_str + "(" + expr1 + ", " + expr2 + ")"
# Define a map with the operator string and the formatter function
# associated with each BinaryOperation.Operator
from psyclone.psyir.nodes import BinaryOperation
opmap = {
BinaryOperation.Operator.ADD: ("+", operator_format),
BinaryOperation.Operator.SUB: ("-", operator_format),
BinaryOperation.Operator.MUL: ("*", operator_format),
BinaryOperation.Operator.DIV: ("/", operator_format),
BinaryOperation.Operator.REM: ("%", operator_format),
BinaryOperation.Operator.POW: ("pow", function_format),
BinaryOperation.Operator.EQ: ("==", operator_format),
BinaryOperation.Operator.NE: ("!=", operator_format),
BinaryOperation.Operator.LT: ("<", operator_format),
BinaryOperation.Operator.LE: ("<=", operator_format),
BinaryOperation.Operator.GT: (">", operator_format),
BinaryOperation.Operator.GE: (">=", operator_format),
BinaryOperation.Operator.AND: ("&&", operator_format),
BinaryOperation.Operator.OR: ("||", operator_format),
BinaryOperation.Operator.SIGN: ("copysign", function_format),
}
arg_nodes = node.items[1].items
if len(arg_nodes) != 2:
raise InternalError(
"Binary operator should have exactly two arguments but "
"found {0} for '{1}'.".format(len(arg_nodes), str(node)))
else:
operator_str = node.items[1].lower()
arg_nodes = [node.items[0], node.items[2]]
try:
operator = Fparser2Reader.binary_operators[operator_str]
except KeyError:
# Operator not supported, it will produce a CodeBlock instead
raise NotImplementedError(operator_str)
binary_op = BinaryOperation(operator, parent=parent)
self.process_nodes(parent=binary_op, nodes=[arg_nodes[0]])
self.process_nodes(parent=binary_op, nodes=[arg_nodes[1]])
return binary_op
# Nodes which do not have Nodes as children and (some) predefined
# scalar datatypes
ZERO = Literal("0.0", REAL_TYPE)
ONE = Literal("1.0", REAL4_TYPE)
TWO = Literal("2.0", SCALAR_TYPE)
INT_ZERO = Literal("0", INTEGER_SINGLE_TYPE)
INT_ONE = Literal("1", INTEGER8_TYPE)
TMP1 = Reference(ARG1)
TMP2 = Reference(TMP_SYMBOL)
# Unary Operation
OPER = UnaryOperation.Operator.SIN
UNARYOPERATION = UnaryOperation.create(OPER, TMP2)
# Binary Operation
OPER = BinaryOperation.Operator.ADD
BINARYOPERATION = BinaryOperation.create(OPER, ONE, UNARYOPERATION)
# Nary Operation
OPER = NaryOperation.Operator.MAX
NARYOPERATION = NaryOperation.create(OPER, [TMP1, TMP2, ONE])
# 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])
'''
if isinstance(node, Fortran2003.Case_Value_Range):
# The case value is a range (e.g. lim1:lim2)
if node.items[0] and node.items[1]:
# Have lower and upper limits so need a parent AND
aop = BinaryOperation(BinaryOperation.Operator.AND,
parent=parent)
parent.addchild(aop)
new_parent = aop
else:
# No need to create new parent node
new_parent = parent
if node.items[0]:
# A lower limit is specified
geop = BinaryOperation(BinaryOperation.Operator.GE,
parent=new_parent)
self.process_nodes(parent=geop, nodes=[selector])
self.process_nodes(parent=geop, nodes=[node.items[0]])
new_parent.addchild(geop)
if node.items[1]:
# An upper limit is specified
leop = BinaryOperation(BinaryOperation.Operator.LE,
parent=new_parent)
self.process_nodes(parent=leop, nodes=[selector])
self.process_nodes(parent=leop, nodes=[node.items[1]])
new_parent.addchild(leop)
else:
# The case value is some scalar initialisation expression
bop = BinaryOperation(BinaryOperation.Operator.EQ,
parent=parent)
parent.addchild(bop)