/******************************************************************************* * * MIT License * * Copyright (C) 2021-2025 Advanced Micro Devices, Inc. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * *******************************************************************************/ #ifndef ROCWMMA_KERNEL_GENERATOR_HPP #define ROCWMMA_KERNEL_GENERATOR_HPP #include #include #include "hip_device.hpp" #include #include namespace rocwmma { /// /// TestParams: nested tuple of kernel parameters to build /// a set of test kernels. E.g. /// /// tuple< tuple, tuple, ...>; /// /// KernelParams: tuple of Params to build a SINGLE kernel. E.g. /// /// tuple; /// /// Workflow: /// /// 1. Build a set of testing kernels with TestParams. /// /// 2. Map KernelParams to the kernel's template arguments. /// This is the responsibility of the kernel generator /// implementation (KernelGeneratorImpl). /// /// 3. Instantiate each set of KernelParams with the impl, /// and return a vector of kernels. /// /// The following utilities are used to build (1). /// - Concat<> /// - CombineOne<> /// - CombineMany<> /// - CombineLists<> /// /// for 2) and 3) KernelGenerator class takes the /// KernelGeneratorImpl and instantiates one kernel /// per tuple of KernelParams from TestParams (1). It /// returns the kernels as a vector. /// There are several classes that provide functionality /// to build combinations of basic types. /// /// Concat: Concatenation of types together. /// E.g. /// Concat( A ) = tuple /// Concat( A, B ) = tuple /// Concat( tuple, B ) = tuple /// Concat( A, tuple ) = tuple /// Concat( tuple, tuple ) = tuple /// Concat( A, B, C, ...) = tuple template struct Concat; template struct Concat { using Result = decltype(std::make_tuple(Arg())); }; template struct Concat> { using Result = std::tuple; }; template struct Concat { using Result = typename Concat::Result, Rest...>::Result; }; template struct Concat { using Result = decltype(std::make_tuple(Lhs(), Rhs())); }; template struct Concat> { using Result = decltype(std::tuple_cat(std::make_tuple(Lhs()), std::tuple())); }; template struct Concat, std::tuple> { using Result = decltype(std::tuple_cat(std::tuple(), std::tuple())); }; template struct Concat, Rhs> { using Result = decltype(std::tuple_cat(std::tuple(), std::make_tuple(Rhs()))); }; /// CombineOne: Creates combinatorial pairs of LHS /// with EACH type of RHS if RHS is a tuple. /// NOTE: First level of tuples are collapsed into /// nested tuples, as required by the generator. /// /// E.g. /// CombineOne( A, B ) = tuple< tuple > /// CombineOne( A, tuple ) = tuple< tuple > /// CombineOne( A, tuple ) = tuple< tuple, /// tuple, /// tuple> /// CombineOne( tuple, tuple ) = tuple< tuple, /// tuple> /// template struct CombineOne { using Result = decltype(std::make_tuple(typename Concat::Result())); }; template struct CombineOne> { using Result = decltype(std::make_tuple(typename Concat::Result())); }; template struct CombineOne> { using Mine = typename Concat::Result; using Next = CombineOne>; using Result = decltype(std::tuple_cat(std::make_tuple(Mine()), typename Next::Result())); }; /// CombineMany: Creates combinatorial pairs two lists: /// EACH type of LHS with EACH type of RHS. /// NOTE: First level of tuples are collapsed into /// nested tuples, as required by the generator. /// /// E.g. /// CombineMany( A, B ) = tuple< tuple > /// CombineMany( A, tuple ) = tuple< tuple > /// CombineMany( A, tuple ) = tuple< tuple, /// tuple, /// tuple> /// CombineMany( tuple, tuple ) = tuple< tuple, /// tuple, /// tuple, /// tuple> template struct CombineMany { using Result = typename CombineOne::Result; }; template struct CombineMany, Rhs> { using Result = typename CombineOne::Result; }; template struct CombineMany, Rhs> { using Mine = typename CombineOne::Result; using Next = CombineMany, Rhs>; using Result = decltype(std::tuple_cat(Mine(), typename Next::Result())); }; /// CombineLists: Creates combinatorial sets from multiple lists. /// /// E.g: /// CombineLists( tuple< tuple >, tuple< tuple > ) = /// tuple< tuple > /// CombineLists( tuple< tuple, tuple >, tuple< tuple, tuple > ) = /// tuple< tuple, tuple, tuple, tuple > template struct CombineLists { using Result = typename CombineMany::Result>::Result; }; template struct CombineLists { using Result = List; }; // Override wrapper to apply to tuples namespace detail { template struct contains_type> : contains_type { }; } // namespace detail /// Kernel Generator /// Requires two inputs: /// TestParams: nested tuple of KernelParams /// GeneratorImpl: a generator class that /// maps KernelParams to instantiation of the /// actual kernel. /// /// NOTE: The GeneratorImpl class decides the final /// generated kernel instantiated type. This class /// simply returns a vector of generated kernels of /// this type. template struct KernelGenerator { template ROCWMMA_HOST static void generate(Ts...) { } }; template struct KernelGenerator, GeneratorImpl> { using ResultT = std::vector; ROCWMMA_HOST static ResultT generate() { auto result = ResultT(); generate(result); return result; } ROCWMMA_HOST static void generate(ResultT& kernels) { // Generates the kernel for the current set of KernelParams auto gen_kernel = [](ResultT& k) { k.push_back(GeneratorImpl::generate(KernelParams())); }; // Advances to the next set of KernelParams auto next_kernel = [](ResultT& k) { KernelGenerator, GeneratorImpl>::generate(k); }; if constexpr(contains_type_v || contains_type_v) { if constexpr(!(bool)ROCWMMA_FP8) { // Current KernelParams have f8: skip kernel on unsupported arch. next_kernel(kernels); return; } // Quirk: Here, the host code supports F8, but doesn't know // if the runtime target supports it. Make sure the runtime // target can support this type, otherwise don't generate the kernel. if constexpr((bool)ROCWMMA_ARCH_HOST) { // Only gfx950 and gfx12 devices support f8 using DeviceInfo = HipDevice; auto arch = DeviceInfo::instance()->getGcnArch(); if(arch != DeviceInfo::hipGcnArch_t::GFX950 && arch != DeviceInfo::hipGcnArch_t::GFX1200 && arch != DeviceInfo::hipGcnArch_t::GFX1201 && arch != DeviceInfo::hipGcnArch_t::GFX1250) { // Current KernelParams have f8: skip kernel on host. next_kernel(kernels); return; } } // Generate kernel gen_kernel(kernels); next_kernel(kernels); } else if constexpr(contains_type_v< float8_fnuz_t, KernelParams> || contains_type_v) { if constexpr(!(bool)ROCWMMA_FP8_FNUZ) { // Current KernelParams have f8_fnuz: skip kernel on unsupported arch. next_kernel(kernels); return; } // Quirk: Here, the host code supports F8_fnuz, but doesn't know // if the runtime target supports it. Make sure the runtime // target can support this type, otherwise don't generate the kernel. if constexpr((bool)ROCWMMA_ARCH_HOST) { // Only gfx94* devices support f8_fnuz using DeviceInfo = HipDevice; auto arch = DeviceInfo::instance()->getGcnArch(); if(arch != DeviceInfo::hipGcnArch_t::GFX942) { // Current KernelParams have f8_fnuz: skip kernel on host. next_kernel(kernels); return; } } // Generate kernel gen_kernel(kernels); next_kernel(kernels); } else { // Generate kernel gen_kernel(kernels); next_kernel(kernels); } } }; } // namespace rocwmma #endif // ROCWMMA_KERNEL_GENERATOR_HPP