blob: e4a85b764d4c3de8020f04c1fec94a1ec5122c0e [file]
.. 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.
Core TVMScript
==============
TIRx kernels use ``tvm_tirx.script.tirx`` for the parser and core IR builders::
from tvm_tirx.script import tirx as Tx
Tx.alloc_tensor(...)
Tile ops and backend-specific namespaces are documented separately in
:doc:`tile`, :doc:`cuda`, and :doc:`ptx`. For the relationship between these
authoring layers and TIRx IR, see :ref:`tirx-programming-model`.
Parser entry points
-------------------
.. automodule:: tvm_tirx.script.tirx
:members: function, jit, inline, macro
:undoc-members:
:no-index:
Core IR builder
---------------
Common statement frames and construction helpers live in
``tvm_tirx.script.ir_builder.frame`` and ``tvm_tirx.script.ir_builder.stmt``. The TIRx
namespace re-exports them alongside its function, tensor/layout, and execution
scope builders. Native shared statement builders live under
``include/tvm/script/ir_builder`` and ``src/script/ir_builder``; dialect-specific
thread-placement and tensor alias policies remain in the TIRx/S-TIR builders.
.. automodule:: tvm_tirx.tirx.script.ir_builder.ir
:members:
:no-index:
:exclude-members: LetAnnotation
.. currentmodule:: tvm_tirx.tirx.script.ir_builder.ir
.. py:class:: LetAnnotation(type_spec=None)
Marker used by ``Tx.let`` and ``Tx.let[dtype]`` annotations to construct an
explicit ``LetStmt``.
Tracing ordinary Python
-----------------------
The native builders also support frontends that execute ordinary Python to
construct IR. ``IRBuilder.line_trace_scope()`` records file-backed Python source
lines. Script-facing void calls automatically emit into an active IRBuilder,
with or without line tracing::
from tvm_tirx.script import tirx as Tx
from tvm_tirx.script.ir_builder import IRBuilder
from tvm_tirx.tirx.script import ir_builder as I
with IRBuilder() as builder:
with I.function_():
I.func_name_("synchronize")
with builder.line_trace_scope():
with Tx.device_entry(
launch=Tx.cuda.LaunchConfig(grid=1, block=32)
):
Tx.ptx["bar.sync"](0)
function = builder.get()
Auto emission applies to script-facing calls through ``Tx``, including PTX
and backend namespaces. A void call returns an ``AlreadyEmitted`` receipt;
passing that receipt to ``evaluate`` or ``emit_`` does not emit it again.
Calls producing values remain expressions. Raw IR constructors such as
``tvm_tirx.ir.Call``, ``tvm_tirx.tirx.op`` and raw backend APIs remain pure even inside
an IRBuilder. Line tracing only supplies source locations; it neither enables
nor disables emission. The trace scope restores its previous trace and location
state on exit, including exceptional exits, and applies only to its owning builder.
Explicit ``with_loc`` and ``at_`` locations compose with the traced lines.
Line tracing excludes TVM and standard-library implementation files. Frontends
can supply additional directories using ``line_trace_scope(exclude_paths=(... ,))``.
User helpers retain their own source line and the caller's location through
``CallSiteLoc``. These locations cover whole lines; the TVMScript parser records
expression ranges. Python loops and branches execute during construction; use
the native statement frames to construct runtime control flow.
Tensor parameters and shared dimensions
---------------------------------------
Traced frontends can bind native types directly with ``I.arg_``. A shared symbolic
dimension imposes the same size constraint on multiple tensor arguments::
n = Tx.Var("n", Tx.int64)
# Inside an I.function_() frame:
x = I.arg_("x", Tx.Tensor((n,), Tx.float32))
y = I.arg_("y", Tx.Tensor((n,), Tx.float32))
The compiled host entry accepts tensor arguments, including PyTorch tensors,
and checks their dtype, rank and shared dimensions. Use independent symbolic
dimensions for unrelated sizes. If the same dimension is also an explicit scalar
parameter, ``I.arg_("n", n)`` binds that existing Var. ``x.data`` and
``x.ptr_to(indices)`` provide pointers inside the function. ``Tx.Ptr`` retains
its raw-pointer ABI and does not imply tensor argument conversion.
Explicit register fragments
---------------------------
A register fragment is an ordinary local tensor with an explicit layout.
For a two-CTA Layout-B accumulator, define the TMEM and register layouts
outside the kernel::
from tvm_tirx.backend.cuda.axis import tid_in_wg
from tvm_tirx.backend.cuda.layout import tmem_mma_operand_layout
from tvm_tirx.tirx.layout import TileLayout, S
layout_b = tmem_mma_operand_layout(
"D", (64, 128), "float32", M=128, cta_group=2)
register_layout = TileLayout(S[(64, 2, 64) : (1 @ tid_in_wg, 64 @ tid_in_wg, 1)])
Inside the kernel, declare the accumulator over its allocated TMEM address,
allocate the register fragment, and prepare matching instruction views::
C = Tx.cuda.decl_tmem(tmem_address, ty_args=[
Tx.Tensor((64, 128), "float32", scope="tmem", layout=layout_b)
])
frag = Tx.alloc_tensor(ty_args=[
Tx.Tensor((64, 128), "float32", scope="local", layout=register_layout)
])
C_words = C.rearrange("(wh r) (wl c) -> (wl wh) r c",
wh=2, r=32, wl=2)
frag_words = frag.rearrange("(wh r) (wl c) -> (wl wh) r c",
wh=2, r=32, wl=2)
Tx.cuda.tile.apply(
Tx.ptx["tcgen05.ld.sync.aligned.32x32b.x64.b32"],
frag_words, C_words, scope="warpgroup")
Tx.ptx.tcgen05.wait__ld.sync.aligned()
``tmem_address`` must name a live allocation with at least 64 columns.
The readback requires a full active warpgroup.
Complete the producing MMA's commit/mbarrier wait and
the required ``tcgen05.fence::after_thread_sync`` before the load.
Layout B stores logical ``C[i,j]`` in TMEM lane
``i + 64*(j//64)`` and column ``j%64``. The register layout assigns that
same element to thread ``i + 64*(j//64)`` and local slot ``j%64``.
The views above both have shape ``(4,32,64)``: ``warp=2*wl+wh`` chooses
the physical 32-lane slab, ``r`` selects its row, and ``c`` selects its
64 columns. Each warp issues one ``.32x32b.x64`` instruction and each
lane receives 64 registers. No temporary copy is needed.
``wait::ld`` makes the loaded registers available to subsequent
instructions; it does not wait for an earlier MMA.
See :doc:`../tile_ops/tcgen05_ld_st` for other native shapes,
pack/unpack, and a complete store/load example.