#ifndef TRITON_IR_UTILITY_H_ #define TRITON_IR_UTILITY_H_ #include "triton/Dialect/Triton/IR/Dialect.h" #include #include namespace mlir { template SmallVector convertType(ArrayRef in) { SmallVector out; for (const auto &i : in) out.push_back(T(i)); return out; } template SmallVector convertType(const VecU &in) { return convertType(ArrayRef(in)); } template Int product(llvm::ArrayRef arr) { return std::accumulate(arr.begin(), arr.end(), 1, std::multiplies{}); } template auto product(const VecT &vec) { return product(llvm::ArrayRef(vec)); } // TODO(jlebar): Rename to ceilOfRatio. template Int ceil(Int m, Int n) { return (m + n - 1) / n; } /// Get the highest power of 2 divisor of an integer. template T highestPowOf2Divisor(T n) { // When n is 0 or min, return the highest power of 2. The min case is handled // separately to avoid underflow when T is a signed integer. Technically // in that case the correct divisor is -n, but this value is outside the // range of possible values, so we take the next best alternative. if (n == 0 || n == std::numeric_limits::min()) { return (static_cast(1) << (sizeof(T) * 8 - 2)); } return (n & (~(n - 1))); } /// Get the next power of 2 for an integer (or the integer itself if it is a /// power of 2). template T nextPowOf2(T n) { if (n == 0) { return 1; } n--; for (unsigned i = 1; i < sizeof(T) * 8; i <<= 1) { n |= n >> i; } return n + 1; } namespace triton { // Many functions here have two overloads, fn(ArrayRef) and fn(const VecT&). // This is helpful because C++ won't both convert a vector to ArrayRef *and* // infer the proper type T in one step. So without the second overload, we // would have to explicitly convert most arguments to ArrayRef at the callsite. template SmallVector applyPermutation(ArrayRef vec, ArrayRef permutation) { static_assert(std::is_integral_v); assert(vec.size() == permutation.size()); // Check that `permutation` is actually a permutation. #ifndef NDEBUG SmallVector sortedPerm(permutation); llvm::sort(sortedPerm); for (U i = 0; i < static_cast(sortedPerm.size()); i++) { assert(sortedPerm[i] == i); } #endif SmallVector ret; ret.reserve(vec.size()); for (const U &i : permutation) { ret.push_back(vec[i]); } return ret; } template auto applyPermutation(const VecT &vec, const PermT &permutation) { return applyPermutation(ArrayRef(vec), ArrayRef(permutation)); } template [[nodiscard]] SmallVector inversePermutation(ArrayRef permutation) { // Check that `permutation` is actually a permutation. #ifndef NDEBUG SmallVector sortedPerm(permutation); llvm::sort(sortedPerm); for (int i = 0; i < sortedPerm.size(); ++i) { assert(sortedPerm[i] == i); } #endif SmallVector ret(permutation.size()); for (int i = 0; i < permutation.size(); ++i) { ret[permutation[i]] = i; } return ret; } template [[nodiscard]] auto inversePermutation(const VecT &permutation) { return inversePermutation(ArrayRef(permutation)); } template [[nodiscard]] SmallVector gather(ArrayRef elems, ArrayRef indices) { SmallVector ret; ret.reserve(indices.size()); for (const U &i : indices) { ret.push_back(elems[i]); } return ret; } template [[nodiscard]] auto gather(const VecT &elems, const IdxT &indices) { return gather(ArrayRef(elems), ArrayRef(indices)); } // Is `vec` [0, 1, ..., n]? Returns true on empty list. template bool isIota(ArrayRef vec) { static_assert(std::is_integral_v); for (T i = 0; i < vec.size(); ++i) { if (vec[i] != i) { return false; } } return true; } template bool isIota(const VecT &vec) { return isIota(ArrayRef(vec)); } // Is `vals` some permutation of the numbers 0..(vals.size()-1)? template bool isPermutationOfIota(ArrayRef vals) { SmallVector sorted(vals); llvm::sort(sorted); return isIota(sorted); } template bool isPermutationOfIota(const VecT &vec) { return isPermutationOfIota(ArrayRef(vec)); } // Is `vec` [i, i+1, ..., i+n]? Returns true on empty list. template bool isConsecutive(ArrayRef vec) { static_assert(std::is_integral_v); for (int i = 1; i < vec.size(); i++) { if (vec[i] != vec[i - 1] + 1) { return false; } } return true; } template bool isConsecutive(const VecT &vec) { return isConsecutive(ArrayRef(vec)); } template auto seq(T start, T end, T step) { auto len = ceil(end - start, step); return llvm::map_range(llvm::seq(0, len), [=](T i) { return start + i * step; }); } // Combine the current mask with the given predicate. Value getPredMask(RewriterBase &rewriter, Type typeLike, Value currentMask, Value pred); } // namespace triton } // namespace mlir #endif