Files
wehub-resource-sync 26446540fa
Lint / lint (push) Has been cancelled
CI / MacOS (push) Has been cancelled
CI / Windows (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:36:25 +08:00

153 lines
5.9 KiB
C++

/*
* 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.
*/
/*!
* \file tvm/tirx/exec_context.h
* \brief Compile-time ExecContext state: the active thread set ``A`` as a
* TileLayout and the (inter, intra) split under the current scope kind,
* threaded through the IR walker so per-op lowerers see the precise execution
* shape at each site.
*
* Mirrors the pure-Python implementation in python/tvm/tirx/exec_context.py.
*/
#ifndef TVM_TIRX_EXEC_CONTEXT_H_
#define TVM_TIRX_EXEC_CONTEXT_H_
#include <tvm/tirx/exec_scope.h>
#include <tvm/tirx/layout.h>
#include <tvm/tirx/var.h>
#include <string>
#include <unordered_map>
#include <vector>
namespace tvm {
namespace tirx {
/*! \brief Warpgroup size in warps (hardware-fixed). */
constexpr int kWgSize = 4;
/*! \brief Active slice offset + stride * [0, extent) encoded on one TileLayout axis. */
struct AxisRange {
PrimExpr extent;
PrimExpr offset;
PrimExpr stride;
/*! \brief Intersect with [lo, hi). Returns false if the result is empty. */
bool Intersect(int64_t lo, int64_t hi, AxisRange* out) const;
/*! \brief Intersect with values satisfying axis % modulus == residue. */
bool Modulo(int64_t modulus, int64_t residue, AxisRange* out) const;
};
/*!
* \brief Active thread set A.
* The source of truth is ``layout``:
* shard = active axes with extents
* offset = per-axis lower bound, possibly a selector PrimExpr
*/
struct ActiveSet {
TileLayout layout;
int64_t size() const;
bool GetAxis(const std::string& axis, AxisRange* out) const;
bool HasAxis(const std::string& axis) const;
ActiveSet WithAxis(const std::string& axis, const AxisRange& range) const;
std::vector<std::string> AxisNames() const;
};
/*!
* \brief One scope_switch split. Fields are sparse dicts keyed by active-set
* axis name, e.g. laneid/warpid/cta_id/wid_in_wg/wgid or factorized CTA axes
* such as cbx/cby/cbz. An empty map denotes the empty layout (e.g. intra under
* scope_kind=thread).
*/
struct ExecSplit {
std::unordered_map<std::string, AxisRange> inter;
std::unordered_map<std::string, AxisRange> intra;
};
/*! \brief Initial A at PrimFunc device entry: all threads active, offsets zero. */
TVM_DLL ActiveSet InitialActiveSet(int64_t lane_ext, int64_t warp_ext, int64_t cta_ext);
TVM_DLL ActiveSet InitialActiveSet(int64_t lane_ext, int64_t warp_ext, int64_t cta_ext,
const std::vector<std::pair<std::string, int64_t>>& cta_axes);
/*!
* \brief Narrow A on the lane bound to ``binding``.
*
* The ScopeBinding maps directly to which native axis (laneid/warpid/cta_id)
* to narrow, and for warpid whether to narrow the full axis (kCtaWarp), the
* outer factor (kCtaWarpgroup), or the inner factor (kWarpgroupWarp).
*
* Bindings with no single-lane representation are conservative: cluster_id is
* not a filter target; flat thread ids are accepted only when the range can be
* represented as a rectangular lane/warp active set.
*/
TVM_DLL bool FilterNarrow(const ActiveSet& A, ScopeBinding binding, int64_t lo, int64_t hi,
ActiveSet* out, std::string* err);
/*!
* \brief Factor A into (inter, intra) for target scope_kind.
*
* Returns false on factoring failure (warpgroup with warpid lane that
* crosses a warpgroup boundary unaligned) and writes reason to *err.
*/
TVM_DLL bool ScopeSwitch(const ActiveSet& A, ScopeKind scope_kind, ExecSplit* out,
std::string* err);
/*! \brief Per-program-point ExecContext: active set + scope kind + split. */
struct ExecContext {
ActiveSet A;
ScopeKind scope_kind = ScopeKind::kThread;
ExecSplit split; // (inter, intra) of current A under current scope_kind
/*! \brief Kernel-entry ctor. */
static ExecContext AtKernelEntry(int64_t lane_ext, int64_t warp_ext, int64_t cta_ext);
static ExecContext AtKernelEntry(int64_t lane_ext, int64_t warp_ext, int64_t cta_ext,
const std::vector<std::pair<std::string, int64_t>>& cta_axes);
/*! \brief Apply filter; scope_kind preserved, split recomputed. */
bool WithFilter(ScopeBinding binding, int64_t lo, int64_t hi, ExecContext* out,
std::string* err) const;
/*! \brief Apply a unique-value selector filter on one scope id Var. */
bool WithSelector(ScopeBinding binding, PrimExpr selector, ExecContext* out,
std::string* err) const;
/*! \brief Apply filter on a factorized CTA axis such as cbx/cby/cbz. */
bool WithCtaAxisFilter(const std::string& axis, int64_t lo, int64_t hi, ExecContext* out,
std::string* err) const;
/*! \brief Apply modulo filter on a factorized CTA axis such as cbx/cby/cbz. */
bool WithCtaAxisModulo(const std::string& axis, int64_t modulus, int64_t residue,
ExecContext* out, std::string* err) const;
};
/*!
* \brief Encode one side of an ExecSplit (inter or intra) as the FFI map used
* by ``DispatchContextNode::{inter, intra}``: axis name -> [extent, offset]
* for unit-stride axes, or [extent, offset, stride] for strided axes.
*/
TVM_DLL ffi::Map<ffi::String, ffi::Array<PrimExpr>> EncodeSplitSide(
const std::unordered_map<std::string, AxisRange>& side);
} // namespace tirx
} // namespace tvm
#endif // TVM_TIRX_EXEC_CONTEXT_H_