/******************************************************************************* * * MIT License * * Copyright (C) 2022-2026 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. * *******************************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace TensileLite { namespace Predicates { /** * \addtogroup Predicates * @{ */ /** * @brief ContractionProblemGemm predicates */ namespace Contraction { struct Free0SizeMultiple : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; Free0SizeMultiple() = default; Free0SizeMultiple(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "Free0SizeMultiple"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (!problem.transposeC01() ? problem.freeSizeA(index) : problem.freeSizeB(index)) % value == 0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int freeSize = !problem.transposeC01() ? problem.freeSizeA(index) : problem.freeSizeB(index); return debugEvalCmp(problem, stream, "prob", freeSize, "%", "sol", value); } }; struct Free1SizeMultiple : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; Free1SizeMultiple() = default; Free1SizeMultiple(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "Free1SizeMultiple"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (!problem.transposeC01() ? problem.freeSizeB(index) : problem.freeSizeA(index)) % value == 0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int freeSize = !problem.transposeC01() ? problem.freeSizeB(index) : problem.freeSizeA(index); return debugEvalCmp(problem, stream, "prob", freeSize, "%", "sol", value); } }; struct BatchSizeMultiple : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; BatchSizeMultiple() = default; BatchSizeMultiple(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "BatchSizeMultiple"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.batchSize(index) % value == 0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.batchSize(index), "%", "sol", value); } }; struct BatchSizeEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; BatchSizeEqual() = default; BatchSizeEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "BatchSizeEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.batchSize(index) == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.batchSize(index), "==", "sol", value); } }; struct SynchronizerSizeCheck : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; std::array value; SynchronizerSizeCheck() = default; SynchronizerSizeCheck(size_t index, std::array value) : index(index) , value(value) { } static std::string Type() { return "SynchronizerSizeCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[5]; if(gsu == -1 || gsu == 1) return 1; // WorkGroup numbers x number of global write instruction x Wave numbers // M/MT0 x N/MT1 x NumElementsPerThread/StoreVectorWidth x x Wavenumbers x batch uint32_t synchronizerUsage = (std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) * std::ceil(static_cast(problem.freeSizeB(0)) / value[1])) * value[2] * value[4] * value[3] * problem.d().sizes()[2]; if(problem.groupedGemm()) return synchronizerUsage <= 409600 * 16 / problem.groupedGemmCount(); else return synchronizerUsage <= 409600 * 16; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { uint32_t synchronizerSize = 409600 * 16; if(problem.groupedGemm()) synchronizerSize /= problem.groupedGemmCount(); return debugEvalCmp( problem, stream, "prob", (std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) * std::ceil(static_cast(problem.freeSizeB(0)) / value[1])) * (value[2]) * (value[4]) * value[3] * problem.d().sizes()[2], ">=", "limit", synchronizerSize); } }; struct BoundSizeMultiple : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; int64_t index; size_t value; BoundSizeMultiple() = default; BoundSizeMultiple(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "BoundSizeMultiple"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(index < 0) return problem.boundSize(problem.boundIndices().size() + index) % value == 0; else return problem.boundSize(index) % value == 0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int index_mod = index < 0 ? problem.boundIndices().size() + index : index; return debugEvalCmp( problem, stream, "prob", problem.boundSize(index_mod), "%", "sol", value); } }; struct ProblemSizeEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; ProblemSizeEqual() = default; ProblemSizeEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "ProblemSizeEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.problemSizes()[index] == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.problemSizes()[index], "==", "sol", value); } }; struct MaxProblemSizeGreaterThan : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t value; MaxProblemSizeGreaterThan() = default; MaxProblemSizeGreaterThan(size_t value) : value(value) { } static std::string Type() { return "MaxProblemSizeGreaterThan"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.maxProblemSize() > value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.maxProblemSize(), ">", "sol", value); } }; // If the tensor contains no free dimensions, then the first batch dimension // serves as the leading free size struct LeadingFree0SizesGreaterOrEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t value; LeadingFree0SizesGreaterOrEqual() = default; LeadingFree0SizesGreaterOrEqual(size_t value) : value(value) { } static std::string Type() { return "LeadingFree0SizesGreaterOrEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { assert(problem.batchIndices().size() <= 1); // TODO: this is not quite right since it assumes batchSize(0) is lowest // order in index assignments // If tensor contains multiple batch dims this may not be true. // Really should modify Contractions.py to select SizeN >= value, based on // desired index requirement return (problem.freeIndicesA().size() ? problem.freeSizeA(0) >= value : problem.batchSize(0) >= value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int size = problem.freeIndicesA().size() ? problem.freeSizeA(0) : problem.batchSize(0); return debugEvalCmp(problem, stream, "prob", size, ">=", "sol", value); } }; struct LeadingFree1SizesGreaterOrEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t value; LeadingFree1SizesGreaterOrEqual() = default; LeadingFree1SizesGreaterOrEqual(size_t value) : value(value) { } static std::string Type() { return "LeadingFree1SizesGreaterOrEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { assert(problem.batchIndices().size() <= 1); // TODO: this is not quite right since it assumes batchSize(0) is lowest // order in index assignments // If tensor contains multiple batch dims this may not be true. // Really should modify Contractions.py to select SizeN >= value, based on // desired index requirement if(problem.groupedGemm()) return (problem.freeIndicesB().size() ? problem.freeSizeB(0) >= value || problem.freeSizeB(0) == 0 : problem.batchSize(0) >= value || problem.freeSizeB(0) == 0); return (problem.freeIndicesB().size() ? problem.freeSizeB(0) >= value : problem.batchSize(0) >= value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int size = problem.freeIndicesB().size() ? problem.freeSizeB(0) : problem.batchSize(0); return debugEvalCmp(problem, stream, "prob", size, ">=", "sol", value); } }; struct SizeEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; SizeEqual() = default; SizeEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "SizeEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.size(index) == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.size(index), "==", "sol", value); } }; struct SizeGreaterThan : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; SizeGreaterThan() = default; SizeGreaterThan(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "SizeGreaterThan"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (problem.size(index) > value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.size(index), ">", "sol", value); } }; struct SizeLessThan : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; SizeLessThan() = default; SizeLessThan(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "SizeLessThan"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (problem.size(index) < value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.size(index), "<", "sol", value); } }; struct SizeMultiple : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; SizeMultiple() = default; SizeMultiple(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "SizeMultiple"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return ((problem.size(index) % value) == 0); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.size(index), "%", "sol", value); } }; struct Range { size_t min = 0; size_t max = std::numeric_limits::max(); }; inline std::ostream& operator<<(std::ostream& stream, Range const& range) { return stream << "min: " << range.min << ", max: " << range.max; } struct SizeInRange : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; Range value; SizeInRange() = default; SizeInRange(size_t index, Range value) : index(index) , value(value) { } static std::string Type() { return "SizeInRange"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (problem.size(index) >= value.min) && (problem.size(index) < value.max); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob_low", problem.size(index), ">=", "sol_low", value.min, "prob_high", problem.size(index), "<", "sol_high", value.max); } }; struct StrideAEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; StrideAEqual() = default; StrideAEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "StrideAEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.a().strides()[index] == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.a().strides()[index], "==", "sol", value); } }; struct StrideBEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; StrideBEqual() = default; StrideBEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "StrideBEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.b().strides()[index] == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.b().strides()[index], "==", "sol", value); } }; struct StrideCEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; StrideCEqual() = default; StrideCEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "StrideCEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.c().strides()[index] == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.c().strides()[index], "==", "sol", value); } }; struct StrideDEqual : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; size_t value; StrideDEqual() = default; StrideDEqual(size_t index, size_t value) : index(index) , value(value) { } static std::string Type() { return "StrideDEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.d().strides()[index] == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.d().strides()[index], "==", "sol", value); } }; struct LDCEqualsLDD : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; static std::string Type() { return "LDCEqualsLDD"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.c().strides()[1] == problem.d().strides()[1]; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob_c_stride", problem.c().strides()[1], "==", "prob_d_stride", problem.d().strides()[1]); } }; struct CEqualsD : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; static std::string Type() { return "CEqualsD"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.cEqualsD(); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.cEqualsD(), "==", "sol", true); } }; struct AmaxDCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; AmaxDCheck() = default; AmaxDCheck(bool value) : value(value) { } static std::string Type() { return "AmaxDCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { bool amaxDStatusEqual = (problem.outputAmaxD() == value); // if value is true, then we also need to check gsu // otherwise we just check outputAmaxD if(value) return amaxDStatusEqual && (problem.getParams().gsu() == 0 || problem.getParams().gsu() == 1); else return amaxDStatusEqual; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob_amaxD=" << problem.outputAmaxD() << " == sol_amaxD=" << value; if(value) details << ", prob_gsu=" << problem.getParams().gsu() << " (must be 0 or 1)"; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct BetaZero : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; BetaZero() = default; static std::string Type() { return "BetaZero"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.beta() == 0.0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.beta(), "==", "sol", 0.0); } }; struct BetaOne : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; BetaOne() = default; static std::string Type() { return "BetaOne"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.beta() == 1.0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.beta(), "==", "sol", 1.0); } }; struct HighPrecisionAccumulateEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; HighPrecisionAccumulateEqual() = default; HighPrecisionAccumulateEqual(bool value) : value(value) { } static std::string Type() { return "HighPrecisionAccumulate"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.highPrecisionAccumulate() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.highPrecisionAccumulate(), "==", "sol", value); } }; struct KernelLanguageCompatible : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; KernelLanguage value; KernelLanguageCompatible() = default; KernelLanguageCompatible(KernelLanguage value) : value(value) { } static std::string Type() { return "KernelLanguageCompatible"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.kernelLanguage() == value || problem.kernelLanguage() == KernelLanguage::Any; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.kernelLanguage(), "==", "sol", value, "prob", problem.kernelLanguage(), "==", "sol_any", KernelLanguage::Any); } }; struct DeterministicModeEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; DeterministicModeEqual() = default; DeterministicModeEqual(bool value) : value(value) { } static std::string Type() { return "DeterministicMode"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.deterministicMode() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.deterministicMode(), "==", "sol", value); } }; struct AIGreaterThanEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; double value; AIGreaterThanEqual() = default; AIGreaterThanEqual(double value) : value(value) { } static std::string Type() { return "AIGreaterThanEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.arithmeticIntensity() >= value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.arithmeticIntensity(), ">=", "sol", value); } }; struct AILessThanEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; double value; AILessThanEqual() = default; AILessThanEqual(double value) : value(value) { } static std::string Type() { return "AILessThanEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.arithmeticIntensity() <= value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.arithmeticIntensity(), "<=", "sol", value); } }; struct AlphaValue : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; ScalarValue value; AlphaValue() = default; AlphaValue(ScalarValue value) : value(value) { } static std::string Type() { return "AlphaValue"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.alphaRestriction() == value || value == ScalarValue::Any; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.alphaRestriction(), "==", "sol", value, "sol", value, "==", "sol_any", ScalarValue::Any); } }; struct BetaValue : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; ScalarValue value; BetaValue() = default; BetaValue(ScalarValue value) : value(value) { } static std::string Type() { return "BetaValue"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.betaRestriction() == value || value == ScalarValue::Any; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.betaRestriction(), "==", "sol", value, "sol", value, "==", "sol_any", ScalarValue::Any); } }; struct TypesEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; TypesEqual() = default; std::array value; static std::string Type() { return "TypesEqual"; } // This function checks if the computeInputType of a problem matches the computeInputType of a // solution. Because for Float8{_fnuz}/BFloat8{_fnuz}, the computeInputTypeA and computeInputTypeB // might be concatenated like this: computeInputTypeAcomputeInputTypeB{_fnuz}, this function // includes special logic to inspect types at the concatenation position. // bool validateComputeType(rocisa::DataType const& problemComputeInputType, bool const isComputeInputTypeA) const { using ArrType = std::array, 4>; // computeInputTypeA corresponds to the first type in the concatenated type ArrType const computeInputTypeAMapping = {{ {rocisa::DataType::BFloat8_fnuz, rocisa::DataType::BFloat8Float8_fnuz}, {rocisa::DataType::Float8_fnuz, rocisa::DataType::Float8BFloat8_fnuz}, {rocisa::DataType::BFloat8, rocisa::DataType::BFloat8Float8}, {rocisa::DataType::Float8, rocisa::DataType::Float8BFloat8} }}; // computeInputTypeB corresponds to the second type in the concatenated type ArrType const computeInputTypeBMapping = {{ {rocisa::DataType::Float8_fnuz, rocisa::DataType::BFloat8Float8_fnuz}, {rocisa::DataType::BFloat8_fnuz, rocisa::DataType::Float8BFloat8_fnuz}, {rocisa::DataType::Float8, rocisa::DataType::BFloat8Float8}, {rocisa::DataType::BFloat8, rocisa::DataType::Float8BFloat8} }}; auto validate = [](ArrType const& arr, rocisa::DataType const& t1, rocisa::DataType const& t2){ if(t1 == t2) return true; return std::any_of(arr.begin(), arr.end(), [&](const auto& p){ return (p == std::make_pair(t1, t2)) or (p == std::make_pair(t2, t1)); }); }; if(isComputeInputTypeA) { // value[4] is computeInputTypeA return validate(computeInputTypeAMapping, problemComputeInputType, value[4]); } else { // value[5] is computeInputTypeB return validate(computeInputTypeBMapping, problemComputeInputType, value[5]); } } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.a().dataType() == value[0] && problem.b().dataType() == value[1] && problem.c().dataType() == value[2] && problem.d().dataType() == value[3] && problem.computeInputTypeA() == value[4] && problem.computeInputTypeB() == value[5]; } virtual std::string toString() const override { return concatenate(this->type(), "(a:", value[0], ", b:", value[1], ", c:", value[2], ", d:", value[3], ", compute input typeA:", value[4], ", compute input typeB:", value[5]); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob_a", problem.a().dataType(), "==", "sol_a", value[0], "prob_b", problem.b().dataType(), "==", "sol_b", value[1], "prob_c", problem.c().dataType(), "==", "sol_c", value[2], "prob_d", problem.d().dataType(), "==", "sol_d", value[3], "prob_compute_a", problem.computeInputTypeA(), "==", "sol_compute_a", value[4], "prob_compute_b", problem.computeInputTypeB(), "==", "sol_compute_b", value[5]); } }; struct OperationIdentifierEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; OperationIdentifierEqual() = default; std::string value; static std::string Type() { return "OperationIdentifierEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.operationIdentifier() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.operationIdentifier(), "==", "sol", value); } }; struct BufferLoadOffsetLimitCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; BufferLoadCheckPacket value; BufferLoadOffsetLimitCheck() = default; BufferLoadOffsetLimitCheck(BufferLoadCheckPacket value) : value(value) { } static std::string Type() { return "BufferLoadOffsetLimitCheck"; } // The min operator is used to handle cases where size_M/size_K is smaller than the value.depthUorMT0 virtual bool operator()(ContractionProblemGemm const& problem) const override { const uint64_t TWO_POW_32 = 4294967296; return multiplyElementSize((problem.a().strides()[1] * std::min(value.depthUorMT0, problem.a().sizes()[1]) + value.shiftPtrElemA), problem.a().elementBytes()) < TWO_POW_32 && multiplyElementSize((problem.b().strides()[1] * std::min(value.depthUorMT1, problem.b().sizes()[1]) + value.shiftPtrElemB) ,problem.b().elementBytes()) < TWO_POW_32; } virtual std::string toString() const override { return concatenate(this->type(), "(DU/MT0:", value.depthUorMT0, ", DU/MT1:", value.depthUorMT1, ", ShiftPtrPadElementA:", value.shiftPtrElemA, ", ShiftPtrPadElementB:", value.shiftPtrElemB, ")"); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "A:(" << problem.a().strides()[1] << "*" << value.depthUorMT0 << "+" << value.shiftPtrElemA << ")*" << problem.a().elementBytes() << "<2^32, B:(" << problem.b().strides()[1] << "*" << value.depthUorMT1 << "+" << value.shiftPtrElemB << ")*" << problem.b().elementBytes() << "<2^32"; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct BufferLoadOffsetLimitCheck_Beta : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t value; BufferLoadOffsetLimitCheck_Beta() = default; BufferLoadOffsetLimitCheck_Beta(size_t value) : value(value) { } static std::string Type() { return "BufferLoadOffsetLimitCheck_Beta"; } // The min operator is used to handle cases where size_N is smaller than the value(usually is MacroTile1) virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.c().empty() || problem.beta() == 0) { return true; } else { const uint64_t TWO_POW_32 = 4294967296; return multiplyElementSize(problem.c().strides()[1] * std::min(value, problem.c().sizes()[1]), problem.c().elementBytes()) < TWO_POW_32; } } virtual std::string toString() const override { return concatenate(this->type(), "(MT1:", value, ")"); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "C:" << problem.c().strides()[1] << "*" << problem.c().elementBytes() << "*" << value << "<2^32"; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct BufferStoreOffsetLimitCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t value; BufferStoreOffsetLimitCheck() = default; BufferStoreOffsetLimitCheck(size_t value) : value(value) { } static std::string Type() { return "BufferStoreOffsetLimitCheck"; } // The min operator is used to handle cases where size_N is smaller than the value(usually is MacroTile1) virtual bool operator()(ContractionProblemGemm const& problem) const override { const uint64_t TWO_POW_32 = 4294967296; return multiplyElementSize(problem.d().strides()[1] * std::min(value, problem.d().sizes()[1]), problem.d().elementBytes()) < TWO_POW_32; } virtual std::string toString() const override { return concatenate(this->type(), "(MT1:", value, ")"); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "D:" << problem.d().strides()[1] << "*" << problem.d().elementBytes() << "*" << value << "<2^32"; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct WorkgroupNumberCheck : public Predicate_CRTP { enum { HasIndex = true, HasValue = true }; size_t index; std::array value; WorkgroupNumberCheck() = default; WorkgroupNumberCheck(size_t index, std::array value) : index(index) , value(value) { } // If the number is larger than 2^24, it may lose precision when converted into fp32. // TODO: REMOVE custom kernel, then REMOVE the behavior that compressed 3 DIM workgroups into 1 DIM #define MAX_WORKGROUP_NUMBER 16777216 static std::string Type() { return "WorkgroupNumberCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[2]; // auto gsu will consider workgroup number, so bypassed if(gsu == -1) return 1; gsu = gsu > 1 ? gsu : 1; return (std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) * std::ceil(static_cast(problem.freeSizeB(0)) / value[1]) * gsu * problem.batchSize(0)) <= MAX_WORKGROUP_NUMBER; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int16_t gsu = problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[2]; if(gsu == -1) { bool rv = (*this)(problem); PredicateDebugger::printRow(stream, rv, this->type(), "auto gsu (bypassed)"); return rv; } gsu = gsu > 1 ? gsu : 1; int workgroupNumber = std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) * std::ceil(static_cast(problem.freeSizeB(0)) / value[1]) * gsu * problem.batchSize(0); return debugEvalCmp(problem, stream, "wg_num", workgroupNumber, "<=", "max", MAX_WORKGROUP_NUMBER); } }; struct PersistentKernelCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; PersistentKernelCheck() = default; static std::string Type() { return "PersistentKernelCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.getPersistentKernelEligibility(); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); PredicateDebugger::printRow( stream, rv, this->type(), rv ? "eligible" : "not eligible"); return rv; } }; struct GlobalSplitUCheckMinK : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; std::array value; GlobalSplitUCheckMinK() = default; GlobalSplitUCheckMinK(std::array value) : value(value) { } static std::string Type() { return "GlobalSplitUCheckMinK"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { size_t minK = (problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[1]); // auto gsu will consider MinK, so bypassed if(minK == -1) return 1; if(minK == 1) minK = 0; minK *= value[0]; return problem.boundSize(0) >= minK; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { size_t gsu = (problem.getParams().gsu() != 0 ? problem.getParams().gsu() : value[1]); if(gsu == static_cast(-1)) { bool rv = (*this)(problem); PredicateDebugger::printRow(stream, rv, this->type(), "auto gsu (bypassed)"); return rv; } size_t minK = (gsu == 1) ? 0 : gsu * value[0]; return debugEvalCmp(problem, stream, "prob", problem.boundSize(0), ">=", "sol", minK); } }; struct CDStridesEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; CDStridesEqual() = default; static std::string Type() { return "CDStridesEqual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.c().strides() == problem.d().strides(); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob_c_stride", problem.c().strides(), "==", "prob_d_stride", problem.d().strides()); } }; struct StridedBatchedEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; StridedBatchedEqual() = default; StridedBatchedEqual(bool value) : value(value) { } static std::string Type() { return "StridedBatched"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.stridedBatched() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.stridedBatched(), "==", "sol", value); } }; struct GroupedGemmEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; GroupedGemmEqual() = default; GroupedGemmEqual(bool value) : value(value) { } static std::string Type() { return "GroupedGemm"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.groupedGemm() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.groupedGemm(), "==", "sol", value); } }; struct CUEfficiency : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; CUEfficiency() = default; static std::string Type() { return "CUEfficiency"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.performanceMetric() == PerformanceMetric::CUEfficiency) { return true; } else if(problem.performanceMetric() == PerformanceMetric::Auto) { // True if total flops below a constant threshold // Current threshold chosen naively as the flops for a // 1500x1500 square matrix multiply return problem.flopCount() < size_t(1500ll * 1500ll * 1500ll * 2); } else { return false; } } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; if(problem.performanceMetric() == PerformanceMetric::CUEfficiency) details << "metric=CUEfficiency"; else if(problem.performanceMetric() == PerformanceMetric::Auto) details << "metric=Auto, flopCount=" << problem.flopCount(); else details << "metric=other (not CUEfficiency or Auto)"; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct ExperimentalStreamK : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; ExperimentalStreamK() = default; static std::string Type() { return "ExperimentalStreamK"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (problem.performanceMetric() == PerformanceMetric::ExperimentalStreamK); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.performanceMetric(), "==", "sol: PerformanceMetric::ExperimentalStreamK", PerformanceMetric::ExperimentalStreamK); } }; struct ExperimentalMLP : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; ExperimentalMLP() = default; static std::string Type() { return "ExperimentalMLP"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return (problem.performanceMetric() == PerformanceMetric::ExperimentalMLP); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp(problem, stream, "prob", problem.performanceMetric(), "==", "sol: PerformanceMetric::ExperimentalMLP", PerformanceMetric::ExperimentalMLP); } }; struct EqualityMatching : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; EqualityMatching() = default; static std::string Type() { return "EqualityMatching"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); stream << "Searching " << this->type() << " Library..." << std::endl; return rv; } }; struct RangeMatching : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; RangeMatching() = default; static std::string Type() { return "RangeMatching"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); stream << "Searching " << this->type() << " Library..." << std::endl; return rv; } }; struct FreeSizeMatching : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; FreeSizeMatching() = default; static std::string Type() { return "FreeSizeMatching"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); stream << "Searching " << this->type() << " Library..." << std::endl; return rv; } }; struct PredictionMatching : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; PredictionMatching() = default; static std::string Type() { return "PredictionMatching"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); PredicateDebugger::printRow(stream, rv, this->type()); return rv; } }; struct GridBasedMatching : public Predicate_CRTP { enum { HasIndex = false, HasValue = false }; GridBasedMatching() = default; static std::string Type() { return "GridBasedMatching"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); PredicateDebugger::printRow(stream, rv, this->type()); return rv; } }; struct UseGradientEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; UseGradientEqual() = default; UseGradientEqual(bool value) : value(value) { } static std::string Type() { return "UseGradient"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.useGradient() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.useGradient(), "==", "sol", value); } }; // Activation struct ActivationCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; ActivationType value; ActivationCheck() = default; ActivationCheck(ActivationType value) : value(value) { } static std::string Type() { return "Activation"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(value == ActivationType::All) return true; if(problem.activationType() == value || problem.activationType() == ActivationType::None) return true; if(value == ActivationType::Hipblaslt_all && (problem.activationType() == ActivationType::DGelu || problem.activationType() == ActivationType::DRelu || problem.activationType() == ActivationType::Gelu || problem.activationType() == ActivationType::Relu || problem.activationType() == ActivationType::Silu || problem.activationType() == ActivationType::Clamp)) return true; return false; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.activationType(), "==", "sol", value); } }; struct ActivationEnumWhiteList : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; ActivationEnumWhiteList() = default; std::vector value; static std::string Type() { return "ActivationEnumWhiteList"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.activationType() == ActivationType::All || problem.activationType() == ActivationType::Hipblaslt_all) { for(size_t i = 0; i < value.size(); i++) { if(value[i] == problem.getParams().activationEnum()) { return true; } } return false; } return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "supported=["; for(size_t i = 0; i < value.size(); i++) { details << ToString(value[i]); if(i < value.size() - 1) details << ", "; } details << "], prob=" << ToString(problem.getParams().activationEnum()); PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct ActivationComputeTypeEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; rocisa::DataType value; ActivationComputeTypeEqual() = default; ActivationComputeTypeEqual(rocisa::DataType value) : value(value) { } static std::string Type() { return "ActivationComputeType"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.activationType() == ActivationType::None) return true; return problem.activationComputeType() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); if(problem.activationType() != ActivationType::None) return debugEvalCmp(problem, stream, "prob", problem.activationComputeType(), "==", "sol", value); return rv; } }; struct ActivationNoGuardEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; ActivationNoGuardEqual() = default; ActivationNoGuardEqual(bool value) : value(value) { } static std::string Type() { return "ActivationNoGuard"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.activationNoGuard() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.activationNoGuard(), "==", "sol", value); } }; struct UseBiasCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; int value; UseBiasCheck() = default; UseBiasCheck(int value) : value(value) { } static std::string Type() { return "UseBias"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return !problem.useBias() || value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob=" << problem.useBias() << ", sol_supports=" << value; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct UseGateResidualEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; UseGateResidualEqual() = default; UseGateResidualEqual(bool value) : value(value) { } static std::string Type() { return "UseGateResidual"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.useGateResidual() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob=" << problem.useGateResidual() << ", sol=" << value; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct UseEEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; UseEEqual() = default; UseEEqual(bool value) : value(value) { } static std::string Type() { return "UseE"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.useE() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.useE(), "==", "sol", value); } }; struct DataTypeEEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; rocisa::DataType value; DataTypeEEqual() = default; DataTypeEEqual(rocisa::DataType value) : value(value) { } static std::string Type() { return "DataTypeE"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.useE()) { return problem.e().dataType() == value; } return true; } virtual std::string toString() const override { return concatenate(this->type(), "(e:", value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); debugEvalCmp( problem, stream, "prob_e", problem.e().dataType(), "==", "sol_e", value); return rv; } }; struct UseScaleABCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; std::string value; UseScaleABCheck() = default; UseScaleABCheck(std::string value) : value(value) { } static std::string Type() { return "UseScaleAB"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.useScaleAB().empty() || (problem.useScaleAB() == value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob=" << problem.useScaleAB() << ", sol_supports=" << value; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct UseScaleCDCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; UseScaleCDCheck() = default; UseScaleCDCheck(bool value) : value(value) { } static std::string Type() { return "UseScaleCD"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return !problem.useScaleCD() || value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob=" << problem.useScaleCD() << ", sol_supports=" << value; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct UseScaleAlphaVecCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; int value; UseScaleAlphaVecCheck() = default; UseScaleAlphaVecCheck(int value) : value(value) { } static std::string Type() { return "UseScaleAlphaVec"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return !problem.useScaleAlphaVec() || (problem.useScaleAlphaVec() & value); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "prob=" << problem.useScaleAlphaVec() << ", sol_supports=" << value; PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct BiasDataTypeWhiteList : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; BiasDataTypeWhiteList() = default; std::vector value; static std::string Type() { return "BiasDataTypeWhiteList"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.useBias()) { for(size_t i = 0; i < value.size(); i++) { if(value[i] == problem.bias().dataType()) { return true; } } return false; } return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "supported_types=["; for(size_t i = 0; i < value.size(); i++) { details << ToString(value[i]); if(i < value.size() - 1) details << ", "; } details << "]"; if(problem.useBias()) details << ", prob_type=" << ToString(problem.bias().dataType()); PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct GateResidualDataTypeWhiteList : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; GateResidualDataTypeWhiteList() = default; std::vector value; static std::string Type() { return "GateResidualDataTypeWhiteList"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.useGateResidual()) { for(size_t i = 0; i < value.size(); i++) { if(value[i] == problem.gateResidual().dataType()) { return true; } } return false; } return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "supported_types=["; for(size_t i = 0; i < value.size(); i++) { details << ToString(value[i]); if(i < value.size() - 1) details << ", "; } details << "]"; if(problem.useGateResidual()) details << ", prob_type=" << ToString(problem.gateResidual().dataType()); PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct BiasSrcWhiteList : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; BiasSrcWhiteList() = default; // This is actually the index of the problem type std::vector value; static std::string Type() { return "BiasSrcWhiteList"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { if(problem.useBias() && problem.useScaleAlphaVec() && problem.useBias() != problem.useScaleAlphaVec()) return false; int factorDim = (problem.useBias() == 1) ? 0 : problem.useBias() == 2 ? 1 : problem.useBias() == 3 ? problem.getParams().factorDim() : 0; if(problem.useBias()) { auto& tensor = problem.tensor(ContractionProblemGemm::TENSOR::BIAS); if(tensor.sizes().size() == 0) return false; for(size_t i = 0; i < value.size(); i++) { if(value[i] == static_cast(problem.biasSrc())) { // Check if the length is set correctly. auto& length = tensor.sizes()[0]; if(problem.biasSrc() == ContractionProblemGemm::TENSOR::A || problem.biasSrc() == ContractionProblemGemm::TENSOR::D) { auto eLength = (problem.useBias() == 1 || problem.biasSrc() != ContractionProblemGemm::TENSOR::D) ? problem.d().sizes()[0] : (problem.useBias() <= 3) ? problem.d().sizes()[factorDim] : -1; if(length < eLength) return false; } else if(problem.biasSrc() == ContractionProblemGemm::TENSOR::B) { if(length != problem.d().sizes()[1]) return false; } return true; } } return false; } return true; } virtual std::string toString() const override { std::string biasString = ""; for(size_t i = 0; i < value.size(); i++) { biasString += ToString(value[i]) + ", "; } return std::string("The supported bias source are: " + biasString); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); std::ostringstream details; details << "supported_sources=["; for(size_t i = 0; i < value.size(); i++) { details << value[i]; if(i < value.size() - 1) details << ", "; } details << "]"; if(problem.useBias()) details << ", bias_src=" << static_cast(problem.biasSrc()); PredicateDebugger::printRow(stream, rv, this->type(), details.str()); return rv; } }; struct Sparse : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; int value; Sparse() = default; Sparse(int value) : value(value) { } static std::string Type() { return "Sparse"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.sparse() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.sparse(), "==", "sol", value); } }; struct SwizzleTensorA : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; SwizzleTensorA() = default; SwizzleTensorA(bool value) : value(value) { } static std::string Type() { return "SwizzleTensorA"; } bool operator()(ContractionProblemGemm const& problem) const override { return problem.swizzleTensorA() == value; } bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.swizzleTensorA(), "==", "sol", value); } }; struct SwizzleTensorB : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; SwizzleTensorB() = default; SwizzleTensorB(bool value) : value(value) { } static std::string Type() { return "SwizzleTensorB"; } bool operator()(ContractionProblemGemm const& problem) const override { return problem.swizzleTensorB() == value; } bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.swizzleTensorB(), "==", "sol", value); } }; struct F32XdlMathOpEqual : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; rocisa::DataType value; F32XdlMathOpEqual() = default; F32XdlMathOpEqual(rocisa::DataType value) : value(value) { } static std::string Type() { return "F32XdlMathOp"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.f32XdlMathOp() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.f32XdlMathOp(), "==", "sol", value); } }; struct SupportDeviceUserArguments : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; bool value; SupportDeviceUserArguments() = default; SupportDeviceUserArguments(bool value) : value(value) { } static std::string Type() { return "SupportDeviceUserArguments"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { // Currently some solutions in gemm cannot enable this feature because lack of sgpr. if(problem.getUseDeviceUserArguments() && problem.groupedGemm()) return problem.getUseDeviceUserArguments() == value; return true; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { bool rv = (*this)(problem); if(problem.getUseDeviceUserArguments()) return debugEvalCmp(problem, stream, "prob", problem.getUseDeviceUserArguments(), "==", "sol", value); return rv; } }; struct WorkgroupMappingXCCCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; // value = [XCC, XCCG] std::array value; size_t cuCount; WorkgroupMappingXCCCheck() { auto pHardware = hip::GetCurrentDevice(); assert(pHardware != nullptr); Hardware const& hardware = *pHardware; AMDGPU const* pAMDGPU = dynamic_cast(&hardware); cuCount = pAMDGPU->computeUnitCount; } WorkgroupMappingXCCCheck(std::array value) : value(value) { auto pHardware = hip::GetCurrentDevice(); assert(pHardware != nullptr); Hardware const& hardware = *pHardware; AMDGPU const* pAMDGPU = dynamic_cast(&hardware); cuCount = pAMDGPU->computeUnitCount; } /// Constructor for testing: inject cuCount so selection logic can be /// unit-tested without a GPU (e.g. ROCM-2963: 38-CU partition alignment). WorkgroupMappingXCCCheck(std::array value, size_t cuCountForTest) : value(value) , cuCount(cuCountForTest) { } static std::string Type() { return "WorkgroupMappingXCCCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { // If XCC == -1, we automatically set it to the number XCCs. // In this case, no predicate is needed. if(value[0] == -1) return true; // NB: If this solution is a cu-fallback for current hardware. // We overwrite the XCC to 1 to make sure this can pass. // But we also have to notice we are passing the correct XCC to kernel. // (i.e. Remember to do param.setWGMXCC(1) when running the kernel) size_t XCC = (problem.getParams().fallbackStatus()) ? 1 : value[0]; size_t XCCG = (value[1] == -1) ? cuCount : value[1]; return ((XCC & (XCC - 1)) == 0) && XCCG % XCC == 0; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { if(value[0] == -1) return true; size_t XCC = (problem.getParams().fallbackStatus()) ? 1 : value[0]; size_t XCCG = (value[1] == -1) ? cuCount : value[1]; return debugEvalCmp(problem, stream, "WGMXCCG", XCCG, "%", "WGMXCC", XCC, "==", 0); } }; struct MXBlockA : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; int value; MXBlockA() = default; MXBlockA(int value) : value(value) { } static std::string Type() { return "MXBlockA"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.mxBlockA() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.mxBlockA(), "==", "sol", value); } }; struct MXBlockB : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; int value; MXBlockB() = default; MXBlockB(int value) : value(value) { } static std::string Type() { return "MXBlockB"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.mxBlockB() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.mxBlockB(), "==", "sol", value); } }; struct DataTypeMXSA : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; rocisa::DataType value; DataTypeMXSA() = default; DataTypeMXSA(rocisa::DataType value) : value(value) { } static std::string Type() { return "DataTypeMXSA"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.mxTypeA() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.mxTypeA(), "==", "sol", value); } }; struct DataTypeMXSB : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; rocisa::DataType value; DataTypeMXSB() = default; DataTypeMXSB(rocisa::DataType value) : value(value) { } static std::string Type() { return "DataTypeMXSB"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { return problem.mxTypeB() == value; } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { return debugEvalCmp( problem, stream, "prob", problem.mxTypeB(), "==", "sol", value); } }; struct ClusterDimCheck : public Predicate_CRTP { enum { HasIndex = false, HasValue = true }; size_t index; std::array value; ClusterDimCheck() = default; ClusterDimCheck(size_t index, std::array value) : index(index) , value(value) { } static std::string Type() { return "ClusterDimCheck"; } virtual bool operator()(ContractionProblemGemm const& problem) const override { int gsu = problem.getParams().gsu() > 0 ? problem.getParams().gsu() : value[2]; gsu = gsu > 1 ? gsu : 1; int numWG_x = static_cast( std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) ); int numWG_y = static_cast( std::ceil(static_cast(problem.freeSizeB(0)) / value[1]) ) * gsu; bool divisible_x = (numWG_x % value[3]) == 0; bool divisible_y = (numWG_y % value[4]) == 0; return (divisible_x and divisible_y); } virtual bool debugEval(ContractionProblemGemm const& problem, std::ostream& stream) const override { int gsu = problem.getParams().gsu() > 0 ? problem.getParams().gsu() : value[2]; gsu = gsu > 1 ? gsu : 1; int numWG_x = static_cast( std::ceil(static_cast(problem.freeSizeA(0)) / value[0]) ); int numWG_y = static_cast( std::ceil(static_cast(problem.freeSizeB(0)) / value[1]) ) * gsu; std::vector numWG = {numWG_x, numWG_y}; std::vector clusterDim = {value[3], value[4]}; return debugEvalCmp(problem, stream, "prob's workgroup number [x, y]", numWG, "%", "cluster dimension [x, y]", clusterDim); } }; } // namespace Contraction /** * @} */ } // namespace Predicates } // namespace TensileLite