153 lines
5.9 KiB
C++
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_
|