Source code for psyclone.psyir.transformations.metatransformations.intrinsic2code_trans
# -----------------------------------------------------------------------------
# SPDX-FileCopyrightText: Copyright (c) 2026 Science and Technology
# Facilities Council
# SPDX-License-Identifier: BSD-3-Clause
# See the full LICENSE file in the project root for details.
# -----------------------------------------------------------------------------
'''This module contains the Intrinsic2CodeTrans metatransformation.'''
from typing import Any
import logging
from psyclone.psyGen import Transformation
from psyclone.psyir.nodes import IntrinsicCall
from psyclone.psyir.transformations.intrinsics.abs2code_trans\
import Abs2CodeTrans
from psyclone.psyir.transformations.intrinsics.dotproduct2code_trans\
import DotProduct2CodeTrans
from psyclone.psyir.transformations.intrinsics.matmul2code_trans\
import Matmul2CodeTrans
from psyclone.psyir.transformations.intrinsics.max2code_trans\
import Max2CodeTrans
from psyclone.psyir.transformations.intrinsics.maxval2loop_trans\
import Maxval2LoopTrans
from psyclone.psyir.transformations.intrinsics.min2code_trans\
import Min2CodeTrans
from psyclone.psyir.transformations.intrinsics.minval2loop_trans\
import Minval2LoopTrans
from psyclone.psyir.transformations.intrinsics.product2loop_trans\
import Product2LoopTrans
from psyclone.psyir.transformations.intrinsics.sign2code_trans\
import Sign2CodeTrans
from psyclone.psyir.transformations.intrinsics.sum2loop_trans\
import Sum2LoopTrans
from psyclone.utils import transformation_documentation_wrapper
[docs]
@transformation_documentation_wrapper
class Intrinsic2CodeTrans(Transformation):
'''This metatransformation applies any of the Intrinsic2Code
transformations to the provided input.
'''
_SUB_TRANSFORMATIONS = [Maxval2LoopTrans, Sum2LoopTrans,
Minval2LoopTrans, Product2LoopTrans,
DotProduct2CodeTrans, Abs2CodeTrans,
Max2CodeTrans, Min2CodeTrans,
Sign2CodeTrans, Matmul2CodeTrans]
# Create a map of intrinsic names to the appropriate Intrinsic2Code
# transformation. This should be in the same order as the
# _SUB_TRANSFORMATIONS else the _split_kwargs on this Transformation
# may not work correctly.
intrinsic_to_trans = {
IntrinsicCall.Intrinsic.MAXVAL: Maxval2LoopTrans,
IntrinsicCall.Intrinsic.SUM: Sum2LoopTrans,
IntrinsicCall.Intrinsic.MINVAL: Minval2LoopTrans,
IntrinsicCall.Intrinsic.PRODUCT: Product2LoopTrans,
IntrinsicCall.Intrinsic.DOT_PRODUCT: DotProduct2CodeTrans,
IntrinsicCall.Intrinsic.ABS: Abs2CodeTrans,
IntrinsicCall.Intrinsic.MAX: Max2CodeTrans,
IntrinsicCall.Intrinsic.MIN: Min2CodeTrans,
IntrinsicCall.Intrinsic.SIGN: Sign2CodeTrans,
IntrinsicCall.Intrinsic.MATMUL: Matmul2CodeTrans}
[docs]
def validate(self, node: IntrinsicCall, **kwargs) -> None:
'''
Validates the input options.
:param node: the IntrinsicCall to be transformed.
:raises TypeError: if the input node is not an IntrinsicCall.
'''
# Validate the provided options are allowed and typed correctly.
self.validate_options(**kwargs)
if not isinstance(node, IntrinsicCall):
raise TypeError(
f"Input node to {self.name} must be an IntrinsicCall but "
f"received '{type(node).__name__}'."
)
def _split_kwargs(self, **kwargs) -> \
tuple[dict[str, Any],
dict[IntrinsicCall.Intrinsic, dict[str, Any]]]:
'''
:returns: the kwargs for this transformation and the kwargs dict for
the sub transformations indexed by appropriate Intrinsic.
'''
# The split_kwargs function returns a tuple containing the
# kwargs for this transformation as the first entry and then
# the kwargs for the SUB_TRANSFORAMTIONS in the same order as the
# following entries.
split_kwargs = self.split_kwargs(**kwargs)
local_kwargs = split_kwargs[0]
sub_kwargs = {}
for i, intrinsic in enumerate(self.intrinsic_to_trans):
sub_kwargs[intrinsic] = split_kwargs[i+1]
return local_kwargs, sub_kwargs
[docs]
def apply(self, node: IntrinsicCall, **kwargs) -> None:
'''
Applies the appropriate Intrinsic2Code transformation to the provided
input node.
:param node: the IntrinsicCall to be transformed.
'''
# Split the options for the subtransformations. The options for
# the subtransforamtions are returned in the kwargs_dict and
# indexed by the relevant intrinsic.
local_kwargs, kwargs_dict = self._split_kwargs(**kwargs)
self.validate(node, **local_kwargs)
# If the intrinsic is one of the supported intrinsics then
# apply the relevant transformation.
if node.intrinsic in self.intrinsic_to_trans:
self.intrinsic_to_trans[node.intrinsic]().apply(
node, **kwargs_dict[node.intrinsic]
)
else:
# Setup the logger.
logger = logging.getLogger(__name__)
supported_intrinsics = []
# We only generate the supported intrinsics list if logging
# is at a high enough level for the logging message to occur.
if logger.isEnabledFor(logging.INFO):
supported_intrinsics = [intrinsic.name for intrinsic in
self.intrinsic_to_trans.keys()]
logger.info(
f"Input node was intrinsic of type '{node.intrinsic.name}' "
f"which is not transformed by {self.name}. Supported "
f"intrinsics are {supported_intrinsics}."
)
__all__ = ["Intrinsic2CodeTrans"]