# SPDX-License-Identifier: Apache-2.0
#
# This file is part of the M2-ISA-R project: https://github.com/tum-ei-eda/M2-ISA-R
#
# Copyright (C) 2022
# Chair of Electrical Design Automation
# Technical University of Munich
"""A transformation module for simplifying M2-ISA-R behavior expressions. The following
simplifications are done:
* Resolvable :class:`m2isar.metamodel.arch.Constant` s are replaced by
`m2isar.metamodel.arch.IntLiteral` s representing their value
* Fully resolvable arithmetic operations are carried out and their results
represented as a matching :class:`m2isar.metamodel.arch.IntLiteral`
* Conditions and loops with fully resolvable conditions are either discarded entirely
or transformed into code blocks without any conditions
* Ternaries with fully resolvable conditions are transformed into only the matching part
* Type conversions of :class:`m2isar.metamodel.arch.IntLiteral` s apply the desired
type directly to the :class:`IntLiteral` and discard the type conversion
"""
from ...metamodel import arch, behav
# pylint: disable=unused-argument
[docs]
def operation(self: behav.Operation, context):
statements = []
for stmt in self.statements:
try:
temp = stmt.generate(context)
if isinstance(temp, list):
statements.extend(temp)
else:
statements.append(temp)
except (NotImplementedError, ValueError):
print(f"cant simplify {stmt}")
self.statements = statements
return self
[docs]
def binary_operation(self: behav.BinaryOperation, context):
self.left = self.left.generate(context)
self.right = self.right.generate(context)
if isinstance(self.left, behav.IntLiteral) and isinstance(self.right, (behav.NamedReference, behav.IndexedReference)):
if self.left.bit_size < self.right.reference.size:
self.left.bit_size = self.right.reference.size
if isinstance(self.right, behav.IntLiteral) and isinstance(self.left, (behav.NamedReference, behav.IndexedReference)):
if self.right.bit_size < self.left.reference.size:
self.right.bit_size = self.left.reference.size
if isinstance(self.left, behav.IntLiteral) and isinstance(self.right, behav.IntLiteral):
# pylint: disable=eval-used
res: int = int(eval(f"{self.left.value}{self.op.value}{self.right.value}"))
return behav.IntLiteral(res, max(self.left.bit_size, self.right.bit_size, res.bit_length()))
if self.op.value == "&&":
if isinstance(self.left, behav.IntLiteral):
if self.left.value:
return self.right
else:
return self.left
if isinstance(self.right, behav.IntLiteral):
if self.right.value:
return self.left
else:
return self.right
if self.op.value == "||":
if isinstance(self.left, behav.IntLiteral):
if self.left.value:
return self.left
else:
return self.right
if isinstance(self.right, behav.IntLiteral):
if self.right.value:
return self.right
else:
return self.left
return self
[docs]
def slice_operation(self: behav.SliceOperation, context):
self.expr = self.expr.generate(context)
self.left = self.left.generate(context)
self.right = self.right.generate(context)
return self
[docs]
def concat_operation(self: behav.ConcatOperation, context):
self.left = self.left.generate(context)
self.right = self.right.generate(context)
return self
[docs]
def number_literal(self: behav.IntLiteral, context):
return self
[docs]
def int_literal(self: behav.IntLiteral, context):
return self
[docs]
def scalar_definition(self: behav.ScalarDefinition, context):
return self
[docs]
def break_(self: behav.Break, context):
return self
[docs]
def assignment(self: behav.Assignment, context):
self.target = self.target.generate(context)
self.expr = self.expr.generate(context)
if isinstance(self.expr, behav.IntLiteral) and isinstance(self.target, (behav.NamedReference, behav.IndexedReference)):
if self.expr.bit_size < self.target.reference.size:
self.expr.bit_size = self.target.reference.size
#if isinstance(self.expr, behav.IntLiteral) and isinstance(self.target, behav.ScalarDefinition):
# self.target.scalar.value = self.expr.value
return self
[docs]
def conditional(self: behav.Conditional, context):
self.conds = [x.generate(context) for x in self.conds]
self.stmts = [x.generate(context) for x in self.stmts]
eval_false = True
conds = []
stmts = []
for cond, stmt in zip(self.conds, self.stmts):
if isinstance(cond, behav.IntLiteral):
if cond.value:
return stmt
else:
conds.append(cond)
stmts.append(stmt)
eval_false = False
if len(self.conds) < len(self.stmts):
if eval_false and isinstance(self.conds[-1], behav.IntLiteral):
if not cond.value: # pylint: disable=undefined-loop-variable
return self.stmts[-1]
stmts.append(self.stmts[-1])
self.conds = conds
self.stmts = stmts
return self
[docs]
def loop(self: behav.Loop, context):
self.cond = self.cond.generate(context)
self.stmts = [x.generate(context) for x in self.stmts]
return self
[docs]
def ternary(self: behav.Ternary, context):
self.cond = self.cond.generate(context)
self.then_expr = self.then_expr.generate(context)
self.else_expr = self.else_expr.generate(context)
if isinstance(self.cond, behav.IntLiteral):
if self.cond.value:
return self.then_expr
return self.else_expr
return self
[docs]
def return_(self: behav.Return, context):
if self.expr is not None:
self.expr = self.expr.generate(context)
return self
[docs]
def unary_operation(self: behav.UnaryOperation, context):
self.right = self.right.generate(context)
if isinstance(self.right, behav.IntLiteral):
# pylint: disable=eval-used
res: int = eval(f"{self.op.value}{self.right.value}")
return behav.IntLiteral(res, max(self.right.bit_size, res.bit_length()))
return self
[docs]
def named_reference(self: behav.NamedReference, context):
if isinstance(self.reference, arch.Constant):
return behav.IntLiteral(self.reference.value, self.reference.size, self.reference.signed)
#if isinstance(self.reference, arch.Scalar) and self.reference.value is not None:
# return behav.IntLiteral(self.reference.value, self.reference.size, self.reference.data_type == arch.DataType.S)
return self
[docs]
def indexed_reference(self: behav.IndexedReference, context):
self.index = self.index.generate(context)
return self
[docs]
def type_conv(self: behav.TypeConv, context):
self.expr = self.expr.generate(context)
if isinstance(self.expr, behav.IntLiteral):
self.expr.bit_size = self.size
self.expr.signed = self.data_type == arch.DataType.S
return self.expr
return self
[docs]
def callable_(self: behav.Callable, context):
self.args = [stmt.generate(context) for stmt in self.args]
return self
[docs]
def group(self: behav.Group, context):
self.expr = self.expr.generate(context)
if isinstance(self.expr, behav.IntLiteral):
return self.expr
return self