# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.
# pylint: disable=invalid-name, unused-argument, redefined-argument-from-local
"""Relax Optimize Layout Transform pass."""

import tvm_ffi

from tvm.ir.module import IRModule
from tvm.ir.transform import PassContext
from tvm.relax import Expr
from tvm.relax.dpl import TuplePattern, is_op, rewrite_call, wildcard

from . import function_pass


@function_pass(opt_level=0)
class OptimizeLayoutTransform:
    """
    Pass to remove redundant transform layout operators
    introduced by AlterOpImpl pass.
    """

    def __init__(self):
        self.input = wildcard()
        pattern_transform_layout = is_op("relax.layout_transform")(self.input)
        pattern_1 = is_op("relax.layout_transform")(pattern_transform_layout)

        self.gv_ = wildcard()
        args = TuplePattern([pattern_transform_layout])
        pattern_2 = is_op("relax.call_tir")(self.gv_, args)
        self.pattern_2 = is_op("relax.layout_transform")(pattern_2)

        self.pattern = pattern_1 | self.pattern_2

    def transform_function(self, func: Expr, mod: IRModule, ctx: PassContext) -> IRModule:
        """
        Tranformation function to pattern match layout_transform -> layout_transform
        pattern

        Parameters
        ----------
        func: Expr
            The relax function to be optimized

        mod: IRModule
            The ir module

        ctx: PassContext
            Relax pass context
        """

        self.mod = mod
        updated_func = func

        # Skip primitive functions
        if "Primitive" in func.attrs.keys() and func.attrs["Primitive"] != 0:
            return updated_func

        def rewriter(expr, matches):
            arg1 = matches[self.pattern]
            if self.pattern_2 not in matches.keys():
                arg2 = matches[self.input]
            else:
                arg2 = matches[self.gv_]
                if "remove_pad" == self.mod[arg2].attrs["operator_name"]:
                    arg2 = matches[self.input]
            if hasattr(arg1.ty, "shape") and hasattr(arg2.ty, "shape"):
                if tvm_ffi.structural_equal(arg1.ty.shape, arg2.ty.shape):
                    return arg2
            return expr

        updated_func = rewrite_call(self.pattern, rewriter, func)

        return updated_func
