# 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=missing-docstring # ruff: noqa: F841 """Pool schedule rule for Adreno operators.""" from tvm import s_tir, tirx from tvm.target import Target from .. import analysis from .base import AdrenoScheduleRule # pylint: disable=invalid-name, unused-variable class Pool2D(AdrenoScheduleRule): def apply( # pylint: disable=too-many-locals,missing-docstring self, func: tirx.PrimFunc, target: Target, _: bool, ) -> s_tir.Schedule: sch = s_tir.Schedule(func) root = sch.get_sblock(name="root", func_name="main") blocks = sch.get_child_blocks(root) blocks_names = [sch.get(blk).name_hint for blk in blocks] if "adaptive_pool_sum" not in blocks_names and "pool_max" not in blocks_names: return None def schedule_pad(blk: s_tir.schedule.SBlockRV): lps, veclp = sch.get_loops(blk)[:-1], sch.get_loops(blk)[-1] sch.vectorize(veclp) b = sch.fuse(*lps) tx_extent = min(int(sch.get(b).extent) & ~int(sch.get(b).extent - 1), 256) bx, tx = sch.split(b, [None, tx_extent]) sch.bind(bx, "blockIdx.x") sch.bind(tx, "threadIdx.x") def schedule_max_pool(blk: s_tir.schedule.SBlockRV): block_info = analysis.get_sblock_info(sch, blk) iters_kind = "".join([_iter.kind for _iter in block_info.iters]) if iters_kind != "SSSSSRR": return None lps = sch.get_loops(blk) block_lps, vec_lp, red_lps = lps[:4], lps[4], lps[5:] write_blk = sch.cache_write(blk, 0, "local") sch.reverse_compute_at(write_blk, vec_lp) b = sch.fuse(*block_lps) tx_extent = min(int(sch.get(b).extent) & ~int(sch.get(b).extent - 1), 256) bx, tx = sch.split(b, [None, tx_extent]) sch.bind(bx, "blockIdx.x") sch.bind(tx, "threadIdx.x") sch.vectorize(vec_lp) return True passed_reduction = False for blk in blocks: if sch.get(blk).name_hint == "pad_temp": schedule_pad(blk) elif ( sch.get(blk).name_hint == "adaptive_pool_sum" or sch.get(blk).name_hint == "pool_max" ): ok = schedule_max_pool(blk) if not ok: return None passed_reduction = True else: try: if passed_reduction: sch.reverse_compute_inline(blk) else: sch.compute_inline(blk) except Exception: # pylint: disable=broad-except pass return sch