112 Commits

Author SHA1 Message Date
Tianqi Chen 80648af29f [REFACTOR][TIR] Remove buffer type and axis separators (#20019) 2026-07-17 17:08:13 +08:00
Tianqi Chen 275114b327 [REFACTOR][IR] Unify PrimExpr with Expr typed view (#19910)
## Summary
- Make `PrimExpr` a typed C++ view over `Expr` values whose
`ExprNode::ty` is `PrimType`, instead of using a separate runtime node
class as the proof of primitive-ness.
- Use the shared `ir::Call` node for Relax, TIRX, and primitive-valued
calls, while keeping primitive-only APIs explicit at their semantic
boundaries.
- Keep Python on the general `Expr` surface for primitive-typed values
so `isinstance` behavior does not imply a nominal primitive-expression
subclass.

## Design Rationale
The main advantage of this change is that common expression nodes such
as `Call` can be unified without specializing each one to `PrimType`. A
single `ir::Call` can represent a Relax tensor call, a Relax scalar
call, or a primitive-valued intrinsic call; the result type stored in
`ExprNode::ty` determines whether that particular value can be viewed as
`PrimExpr`.

This keeps the IR node hierarchy focused on expression structure rather
than result-type categories. Nodes that are intrinsically primitive,
such as integer and floating-point literals or TIRX primitive operators,
still have strongly typed C++ APIs and data structures. General nodes
whose result type may vary, such as `Call`, remain general `Expr` nodes
and are narrowed to `PrimExpr` only where primitive-only semantics are
required.

The PR also keeps the compatibility surface practical: C++
primitive-only APIs continue to accept `PrimExpr`, Python exposes a
compatibility predicate for checking the primitive typed category, and
visitors/printers use one natural `Call` path rather than duplicating
Relax and primitive call handling. Missing expression types are
represented explicitly with `Type::Missing()` so constructors can leave
type inference to later analysis without relying on nullable `Type`
values.
2026-07-01 18:55:33 -04:00
Tianqi Chen f3f5a3e42a [REFACTOR][RELAX] Rename Relax base type to AnyType (#19889)
This PR introduces Relax AnyType as the primary top/base type spelling,
replacing the previous ObjectType naming for the type that represents
any Relax value.

Changes:
- Add AnyType/AnyTypeNode with relax.AnyType registration and keep
ObjectType/R.Object compatibility aliases.
- Update Relax type analysis, type visitors, opaque function defaults,
and script printer/parser handling to use AnyType/R.Any.
- Migrate affected Python/C++ call sites, docs, and focused tests to the
new spelling.

Validation:
- cmake --build build --parallel 16
- Focused Relax/TVMScript pytest: 704 passed, 1 xfailed
- pre_commit run --files <changed files>
2026-06-25 13:29:10 -04:00
Tianqi Chen 1bb5cf6102 [REFACTOR][IR] Unify StructInfo and Type (#19853)
## Summary

- unify Relax's former StructInfo surface into the Type vocabulary and
Expr.ty storage path
- remove leftover DependentTypeNode and legacy OpNode::op_type storage
- keep base Type nullable while concrete Relax/DTensor type refs are
non-nullable
- clean stale StructInfo/TensorStructInfo/sinfo vocabulary in
Python/docs and distributed-op macros
- address Gemini follow-ups for parser annotations, BlockBuilder
docstring, and Adreno TensorType cast audit
2026-06-21 10:12:12 -04:00
Bohan Hou 859498dc01 [TIRx] Bringup TIRx Infrastructure (#19581)
## Summary

This PR adds the initial TIRx support needed for low-level programming
of Blackwell-class GPU architectures. As part of the ongoing TIRx
refactor, it introduces TVMScript support for directly scripting
advanced hardware features without relying on scheduling as the primary
programming interface.

The change keeps existing `s_tir` script support intact while making
direct scripting a first-class path for TIRx programs.

## Main Changes

- Add TIRx operator dispatch and layout infrastructure.
- Add TVMScript support for new low-level TIRx operations.
- Add analysis, transform, and lowering support for TIRx IR nodes.
- Add CUDA/Blackwell-oriented codegen and intrinsic coverage.
- Add Python and C++ integration points for TIRx scripting and runtime
support.

## Validation

- `pre-commit run --all-files`
- `ninja -C build -j32`
- `CUDA_VISIBLE_DEVICES=2 pytest tests/python/tirx/ -n 16`
  - `1723 passed, 47 skipped, 32 warnings`
- `CUDA_VISIBLE_DEVICES=2 python -m pytest -v
tests/python/all-platform-minimal-test`
  - `37 passed, 105 skipped`
- `TVM_TEST_TARGETS=llvm python -m pytest -v tests/python/tirx-analysis
tests/python/tirx-base tests/python/tirx-transform -n 16`
  - `664 passed, 25 skipped, 9 xfailed, 1 xpassed`

## Local CI Notes

Some full CI-equivalent jobs were not locally reproducible because this
machine is missing parts of the Apache TVM CI environment, including
`llvm-config-15/17`, Vulkan, ROCm, Maven, Sphinx, Doxygen, Emscripten,
and ARM/QEMU cross-toolchain components. Metal-specific tests were
skipped locally because no Metal runtime is available.
2026-05-18 16:44:43 -07:00
Tianqi Chen 9edd5bd958 [REFACTOR] Remove tvm.runtime.packed_func and container shims; route via tvm_ffi (#19442)
## Summary

- Delete the three Python shim modules that re-exported tvm-ffi types
under `tvm.runtime` / `tvm.ir`:
`python/tvm/runtime/packed_func.py`, `python/tvm/runtime/container.py`,
`python/tvm/ir/container.py`.
- Drop the matching re-exports from `tvm.runtime`, `tvm.ir`, and `tvm`
package init files, so
`tvm.runtime.PackedFunc`, `tvm.runtime.ShapeTuple`,
`tvm.runtime.String`, `tvm.ir.Array`,
  `tvm.ir.Map`, and `tvm.container.Array` no longer exist.
- Migrate every productive caller, test, and tutorial to the canonical
names: `tvm_ffi.Function`,
`tvm_ffi.Shape`, `tvm_ffi.core.String`, `tvm_ffi.Array`, and
`tvm_ffi.Map`.

## Test plan

- [x] `pytest tests/python/all-platform-minimal-test` (75 passed, 77
skipped)
- [x] `pytest tests/python/runtime/test_runtime_container.py
tests/python/all-platform-minimal-test/test_runtime_packed_func.py` (20
passed)
- [x] `pytest tests/python/ir/test_node_reflection.py
tests/python/ir/test_container_structural_equal.py` (32 passed)
- [x] `pytest tests/python/relax/test_vm_build.py
tests/python/relax/test_vm_execbuilder.py
tests/python/relax/test_vm_codegen_only.py` (125 passed, 2 xfailed)
- [x] `pytest tests/python/relax/test_runtime_builtin.py
tests/python/relax/test_op_misc.py` (19 passed)
- [x] `pytest tests/python/target/test_target_target.py` (37 passed, 3
skipped)
- [x] `pre-commit run` clean on touched files
2026-04-25 11:02:08 -04:00
Ruslan Baratov eb531188f2 [DOC] Fix various issues (#18966)
- Fix few typos
- Unify Android naming
- Fix HTTPS link
2026-04-02 11:47:09 -04:00
Tianqi Chen 141c22fd8a [Refactor] Bring up tirx namespace (#18913)
This PR brings up the tirx namespace. We have been spliting out the
original tir namespace to include high-level component s_tir and this PR
updates the remaining low-level part as tirx namespace
2026-03-19 21:27:54 -07:00
Tianqi Chen c481950807 [Relax][Refactor] Phase out FewShotTuning (#18864)
## Summary

- Remove `FewShotTuning` pass from Relax transform (C++ implementation,
Python bindings, and test file)
- The pass is unused in the current codebase and can be safely removed

## Files Changed

- `include/tvm/relax/transform.h` — Remove declaration
- `python/tvm/relax/transform/__init__.py` — Remove from imports
- `python/tvm/relax/transform/transform.py` — Remove Python function
- `src/relax/transform/few_shot_tuning.cc` — Delete (C++ implementation)
- `tests/python/relax/test_transform_few_shot_tuning.py` — Delete (test
file)
2026-03-02 12:49:42 -05:00
Tianqi Chen 9a8320acbd [LINT][PYTHON] Modernize annotations with ruff UP rules (#18830)
This PR enables ruff pyupgrade (UP) rules with py310 target, auto-fixing
~5600 annotation modernizations (PEP 585 generics, PEP 604 unions,
deprecated typing imports).

Also removes from __future__ import annotations from ir/module.py and
rmsnorm.py, bumps requires-python to >=3.10, and removes absolute_import
aliases from topi/contrib files.
2026-02-27 21:29:47 -05:00
Tianqi Chen 33dcea1686 [REFACTOR][LINT] Modernize ruff config (#18810)
This PR removes the extra lint violations from the codebase so lint
aligns with the latest style
2026-02-23 07:29:21 -05:00
Tianqi Chen aa2e609136 [LINT] Modernize lint to use pre-commit hooks (#18807)
This PR migrates existing lint to use pre-commit hooks
2026-02-22 11:03:21 -05:00
Ruslan Baratov 1ebd5e060e [DOC] Fix docstring, unify CMake, nvidia-docker deprecation (#18799)
- Fix docstring in transform.py
- Unify CMake naming
- nvidia-docker is deprecated
2026-02-19 15:01:27 -05:00
thecaptain789 d23d1dbc24 fix: correct typos in Python docstrings (#18727)
Fixed 'occured' to 'occurred' in transform.py and 'seperated' to
'separated' in mrvl.py.

Co-authored-by: thecaptain789 <thecaptain789@users.noreply.github.com>
2026-02-07 15:32:21 -05:00
Tianqi Chen 877b448b02 [REFACTOR][TIR] Rename tir.Block to SBlock (#18689)
This PR renames tir.Block to SBlock. This clearly indicate the
scheduable property of the block and is a prereq for followup stir
passes refactor.

Main changes:

- Data structure change from Block to SBlock
- Syntax change from T.block to T.sblock
2026-01-28 08:02:10 -05:00
Siva d8c973e674 [RELAX][LAYOUT] Support for dynamic layout specification (#18675)
This allows user defined callback to specify layouts dynamically based
on call description.
Helpful to alter layouts based on the operator shapes or attributes.

---------

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
2026-01-20 21:33:15 +08:00
Siva 4be951d710 [RELAX][PASS] Annotate Custom Scope layout pass for Adreno GPU (#17599)
This PR adds custom scope layout passes for Andreno GPU

https://discuss.tvm.apache.org/t/rfc-annotate-custom-scope-layout-relax-pass-for-adreno-gpu/18052/6

for details about texture scope handling.
2025-11-24 08:33:36 -05:00
Tianqi Chen a21e0df4b3 [FFI][ABI] Bump version ffi to latest (#18332)
This PR bumps the version of tvm-ffi to latest, which involves an ABI change.
2025-09-23 19:50:16 -07:00
Tianqi Chen 3c36ce2ec6 [FFI][REFACTOR][ABI] Rename NDArray to Tensor (#18275)
This PR Updates the NDArray => Tensor.

Both tensor and ndarray are commonly used terms.

Because the term Tensor is getting more common in the context of ML,
we do the rename to stay more aligned with torch.Tensor and DLTensor.
2025-09-06 14:33:59 -07:00
Tianqi Chen a7a0168be5 [FFI][REFACTOR] Establish tvm_ffi python module (#18226)
* [FFI][REFACTOR] Establish tvm_ffi as a standalone python module

This PR establishes tvm_ffi as a standalone python module.
The ffi is structured as a minimal pip module that can be
directly install by path or url.

examples/get_started provided a minimal example.
This is a major change as we are decoupling tvm_ffi as a
separate package, users need to install tvm_ffi separately.

Thanks to its minimal dependency, tvm_ffi can be easily installed
even just from the source by pip install ./ffi

This change would enable future improvement for library plugins
to have lightweight dependencies by just working on top of
the tvm_ffi, while the main compiler toolchain and runtime
can be layered on top.

* [FFI] Improve traceback setups

This PR improves traceback related setups
2025-08-24 15:46:20 -07:00
Tianqi Chen 10e66934ec [REFACTOR] Phase out the RelaxExpr.checked_type in favor of struct_info (#18078) 2025-06-18 16:39:06 -04:00
Tianqi Chen 4289efa0d5 [REFACTOR][PYTHON] Phase out tvm._ffi and Limited API support (#18020)
This PR phases out tvm._ffi redirections in favor of new FFI
new functions are now called via tvm.ffi.

We also enabled limited API support for python 3.12+
so the compiled binary can be forward compatible to future
python versions.
2025-05-28 16:52:36 -04:00
Tianqi Chen 95d1268982 [REFACTOR] Introduce and modernize FFI system (#17920)
This PR modernizes the FFI foundation of the project and introduce
a new minimal and lightweight module [tvm ffi](https://github.com/apache/tvm/tree/refactor-s3/ffi)
based on our lessons in the past few years. It implements a modern
version of the [Unified Packed and Object RFC](https://github.com/apache/tvm-rfcs/blob/main/rfcs/0097-unify-packed-and-object.md)
that unifies the packed function call and object systems.

Summary of the change:
- A dedicated clean Any/AnyView that can store strong and weak
references of items
- Function(previously PackedFunc) system built on top of the Any/AnyView
- A minimal C API that backs the overall calls. We are stabilizing the
API with a goal to bring clean, stable FFI conventions for both compiled
and registered code
- A rewrite of core python binding and generated code based on the module
- Update existing code and test cases to the new module
- Latest dlpack support
 
The new module brings many benefits thanks to the cleaner design,
to name a few:
- Any can support both POD types(int) and object types.
- Containers (e.g. Array) can now also contain Any value, e.g. now
`Array<int>` is supported, no need for boxed types
- Error handling now upgrades to object-based, allowing cleaner
traceback across languages
- Map now preserves insertion orders
- Path toward isolated stabilize minimum core ABI/API foundation module
- Type traits based design that cleanly defines how values interact
with Any system
- Automatic conversion of different types based on traits if needed 

Because FFI upgrade is at heart of the project, the change touches every
component of the system. Importantly, this is an upgrade of the ABI so the
change is not backward compatible.  The code compiled under the old
FFI won't work under the new one. We did provide example ABI translation
(e.g. LegacyTVMArgValueToFFIAny) functions for compatibility. 
The PR tries to leave files in their old places while creating redirections.
The goal is to have the first milestone landed and infrastructure in place,
so we can do further refactors to complete features and cleanup legacy code
as trackable PRs. As of now, python binding and compiled code are under the
new convention while RPC and some  other bindings still relies on legacy ABI
translation. We will work on upgrades in the coming PRs, including areas such
as reflection, phasing out legacy redirections etc.
2025-05-06 19:18:33 -04:00
PatrikPerssonInceptron ef7b7ad3b9 updated the assert in BindParams to allow tvm.relax.Constant (#17693)
* updated the assert in BindParams to allow tvm.relax.Constant in the input dictionary

* fixed linting
2025-03-03 08:39:31 -08:00
Siyuan Feng 80250411e7 [Relax][MetaSchedule] Support CPU weight prepack (#17445)
This PR adds support for CPU weight prepacking. To be specific, this PR
adds a new pass `AttachAttrLayoutFreeBuffers` to attach layout free buffers
to the weight parameters, so that we can leverage MetaSchedule to optimize
the prepacking process.

After the pass and tuning, we introduce a new pass `SplitLayoutRewritePreproc`
to split the layout rewrite pass into multiple functions, so that we can lift
the parameters transform pass function with existing pass.
2024-10-16 16:36:41 -04:00
Siyuan Feng 7569148c3c [Relax] Introduce static shape tuning pipeline (#17428)
This PR introduces a static shape tuning pipeline for Relax. It is designed to work with
the MetaSchedule tuning framework to optimize the performance of the model.

Together with a minor typo fix
2024-09-30 09:07:01 -04:00
Siyuan Feng 9e865b4b8f [Docs] Introduce Relax API and move legacy part to standalone page (#17286)
* [Docs] Introduce Relax API and move legacy part to standalone page

As the TVM project evolves, the Unity strategy has been the recommended
way to use Apache TVM applications. Hence, we are pushing documentation
for the Relax API to the forefront and moving the legacy part to a
standalone page, which may be removed in the future.

* update for ci

* update for ci
2024-08-22 18:16:56 -04:00
Wuwei Lin 05e2bc3340 [Relax] Implement R.ensure_zero_offset and update memory planning for R.view (#17145)
Previously, `R.view` was legalized to extern call to
`runtime.TVMArrayCreateView` during `LegalizeOps`. This call to extern
func can't be properly handled by `StaticBlockPlanMemory` because it
assumes the extern func does not retain the input buffer. Extern func
returning a view of the input would break the ref count of the
buffer. This PR defers the legalization of `R.view` so that it can be
explicitly handled by memory planning.

A new op `R.ensure_aligned` is added as discussed in #16955
2024-08-06 09:13:49 -05:00
Abhikrant Sharma ab7c1a91d8 [Relax] Support input_axis_separator to allow 2D to 1D conversion (#17115)
* [Relax] Support input axis_separator to allow 2D to 1D conversion

Introduce input_axis_separator in relax.transform_layout op to allow conversion of 2D buffers to 1D buffers.
The conversion from 2D->1D is handled while lowering of transform_layout operator.
Also introducing support for input_axis_separator in AlterOpImpl pass.

* Fix LINT errors

* Fix review comments
2024-07-01 12:31:07 +05:30
Wuwei Lin 59376eeca3 [Relax] Allow specifying entry_funcs for BYOC (#16902)
* [Relax] Allow specifying entry_funcs for BYOC
2024-04-18 11:50:55 -04:00
Eric Lunderberg 61249b41ce [Relax][Transform] Provide callback versions of LazyTransformParams (#16798)
* [TIR][Analysis] Implemented tir.analysis.is_pure_function

This commit introduces two related utilities,
`tir.analysis.is_pure_function` and `tir.analysis.assert_pure_function`.
In contrast to the existing `tvm::tir::SideEffect`, which checks for
side effects on a for a `PrimExpr`, `is_pure_function` checks for side
effects for the function as a whole.

* [Transform] Implement relax.transform.ComputePrimValue

Prior to this commit, while expressions of type `DataType::Int(64)`
could be computed in the `relax.transform.VMShapeLower`, expressions
of any other type could not.  This commit introduces
`relax.transform.ComputePrimValue`, which produces `PrimFunc`
subroutines to compute `PrimExpr` values of any dtype.

This functionality will allow boolean values to be computed based on
the symbolic values known at runtime.

* [Relax] Allow R.Prim('bool') in relax::If and assert_op

Prior to this commit, the condition used for `relax::If` node and the
`"relax.assert_op"` operator was required to be a scalar tensor.  This
made it difficult to alter behavior based on a runtime shape
parameter.  For example, delegating to a vectorized implementation
based on a whether a tensor shape is divisible by the vector size.

This commit adds support for expressions of type `R.Prim('bool')` as
the conditional for `relax::If` and `"relax.assert_op"`, to allow
these use cases.

* [Relax][Transform] Provide callback versions of LazyTransformParams

Prior to this commit, the `LazyTransformParams` function could be used
to load model parameters on demand.  However, the function used to
load or set parameters needed to be registered within the global
registry of `PackedFunc`s.  This PR provides `LazyGetInput` and
`LazySetOutput` transforms, which perform the lazy-loading through a
`R.Callable` callback argument, rather than through a
globally-registered `PackedFunc`.

* Reverse the order of parameters in fget_param

If `fget_param` accepts the parameter index first, and the parameter
name second, then an implementation with signauture and default values
of `def fget_param(index: int, name: Optional[str]=None)` could be
used as either the callback of `LazyGetInput`, or as the
globally-registered `"get_item"` for the existing
`LazyTransformParams`, which should make it easier to transition
between the two.

* lint fix

* Updates based on review comments
2024-04-03 11:25:59 -05:00
Eric Lunderberg eb5458e0e9 [Relax] Allow R.Prim('bool') in relax::If and assert_op (#16642)
* [TIR][Analysis] Implemented tir.analysis.is_pure_function

This commit introduces two related utilities,
`tir.analysis.is_pure_function` and `tir.analysis.assert_pure_function`.
In contrast to the existing `tvm::tir::SideEffect`, which checks for
side effects on a for a `PrimExpr`, `is_pure_function` checks for side
effects for the function as a whole.

* [Transform] Implement relax.transform.ComputePrimValue

Prior to this commit, while expressions of type `DataType::Int(64)`
could be computed in the `relax.transform.VMShapeLower`, expressions
of any other type could not.  This commit introduces
`relax.transform.ComputePrimValue`, which produces `PrimFunc`
subroutines to compute `PrimExpr` values of any dtype.

This functionality will allow boolean values to be computed based on
the symbolic values known at runtime.

* [Relax] Allow R.Prim('bool') in relax::If and assert_op

Prior to this commit, the condition used for `relax::If` node and the
`"relax.assert_op"` operator was required to be a scalar tensor.  This
made it difficult to alter behavior based on a runtime shape
parameter.  For example, delegating to a vectorized implementation
based on a whether a tensor shape is divisible by the vector size.

This commit adds support for expressions of type `R.Prim('bool')` as
the conditional for `relax::If` and `"relax.assert_op"`, to allow
these use cases.

* Lint fix
2024-03-28 16:53:47 -05:00
Xiyou Zhou ff6ce9c2b3 Enable Shared Function in LiftTransformParam Pass (#16717)
* [WIP] LiftTransformParams for multiple functions

* pass test

* [In-Progress] Define desired behavior for shared LiftTransformParams

Currently, the `relax.transform.LiftTransformParams` pass produces a
separate `transform_params` function for every function in the
`IRModule`.  In most cases, the functions in an `IRModule` all accept
the same set of model weights (e.g. `"prefill"` and `"decode"` in a
transformer model).  However, the lifted `*_transform_params`
functions may be different for each inference function.

The goal is to introduce a new optional parameter `shared_transform`
for `LiftTransformParams`.  If set, a single parameter transformation
function should be generated for the entire `IRModule`, rather than
one parameter transformation function for each original function.

Because the shared parameter transformation function must be
compatible with all existing functions, it should only contain
parameter transformation steps that are common across all input
functions.

* [TIR] Implemented shared lift transform params

* Comments & skip test.

* Linting.

* Avoid c++20 feature to pass CI.

* Remove unused code.

* Fix interface as suggested.

* Fix docs.

* Fix interface as suggested.

* Move code for readability.

---------

Co-authored-by: Wuwei Lin <wuwei@apache.org>
Co-authored-by: Eric Lunderberg <elunderberg@octoml.ai>
2024-03-19 08:45:03 -07:00
Eric Lunderberg fbfa926585 [Relax] Implement relax.transform.TopologicalSort (#16697)
* [Relax] Implement relax.transform.TopologicalSort

This commit implements a utility `relax.transform.TopologicalSort`,
which can re-order the bindings that occur in a
`relax.DataflowBlock`.  This is not intended for use in a
general-purpose optimization pipeline, but instead as a utility that
may be used as needed in specific cases.  For example, normalization
of unit tests that should not depend on the order of variable binding.

* Update docstring according to review comment
2024-03-18 07:17:18 +09:00
Eric Lunderberg b5815753dc [Transform] Implement relax.transform.ReorderPermuteDimsAfterConcat (#16596)
* [Transform] Implement relax.transform.ReorderPermuteDimsAfterConcat

This commit implements an optional optimization pass
`relax.transform.ReorderPermuteDimsAfterConcat`, which reorder
expressions of the form `R.concat(R.permute_dims(A),
R.permute_dims(B))` into `R.permute_dims(R.concat(A,B))`.

This pass is intended to be used alongside `CombineParallelMatmul`.
After parallel matmuls are combined, to be lifted out, and optimized
`nn.Linear` kernels to find the `R.matmul(x, R.permute_dims(weights))`
patterns they are looking for.

```python
@R.function
def func(x: R.Tensor, weight_query: R.Tensor, weight_key: R.Tensor, weight_value: R.Tensor):
    """Initial IRModule

    The `R.permute_dims` followed by `R.matmul` is the relax
    equivalent of `nn.Linear`, and will frequently have optimized
    kernels.
    """
    weight_query_T = R.permute_dims(weight_query)
    query = R.matmul(x, weight_query)
    weight_key_T = R.permute_dims(weight_key)
    key = R.matmul(x, weight_key)
    weight_value_T = R.permute_dims(weight_value)
    value = R.matmul(x, weight_value)

@R.function
def func(x: R.Tensor, weight_query: R.Tensor, weight_key: R.Tensor, weight_value: R.Tensor):
    """After `CombineParallelMatmul`

    There's now only a single matmul to be performed, which is
    generally better than performing three small matmuls.  However,
    the optimized kernels for `nn.Linear` can no longer be applied,
    because the `R.concat` isn't part of the expected pattern.
    """
    weight_query_T = R.permute_dims(weight_query)
    weight_key_T = R.permute_dims(weight_key)
    weight_value_T = R.permute_dims(weight_value)

    fused_weight_T = R.concat([weight_query_T, weight_key_T, weight_value_T], axis=1)
    fused_qkv = R.matmul(x, fused_weight_T)

    query, key, value = R.split(fused_qkv)

@R.function
def func(x: R.Tensor, weight_query: R.Tensor, weight_key: R.Tensor, weight_value: R.Tensor):
    """After `ReorderPermuteDimsAfterConcat`

    There's still only a single matmul, and the optimized kernels for
    `nn.Linear` can be applied again.
    """
    fused_weight = R.concat([weight_query, weight_key, weight_value], axis=0)

    fused_weight_T = R.permute_dims(fused_weight)
    fused_qkv = R.matmul(x, fused_weight_T)

    query, key, value = R.split(fused_qkv)
```

* Expand description of `max_concat` variable as a temporary solution
2024-02-23 08:28:13 -06:00
Eric Lunderberg fcfc05bb29 [Transform] Allow explicit name of bundled model parameters (#16597)
In `BundleModelParams`, allow the user to specify a name for the tuple
parameters.  If unspecified, defaults to the previous name
`"model_params"`.
2024-02-22 11:19:12 -06:00
Steven S. Lyubomirsky 6a2459f185 [Unity][Doc] Document passes that depend on DataflowBlocks and encourage using ConvertToDataflow (#16514)
* Indicate in doc comments which passes need dataflow blocks

* Also encourage users to use ConvertToDataflow

* Whitespace
2024-02-06 08:00:10 -08:00
Eric Lunderberg 147ed5e27d [Unity][CodeGen] RunCodegen based on externally-exposed functions (#16422)
* [IR] Add utility methods to IRModule

* `IRModule.clone`: Clone the module.  While in C++, a module can be
  copied using `IRModule::CopyOnWrite()`, copying a module in Python
  required passing all members into the `IRModule` initializer.  The
  `IRModule.clone` method provides an easier way to copy an `IRModule`
  from python.

* `IRModule.__delitem__`: Remove a function from the module.  This
  exposes the C++ method `IRModuleNode::Remove` for use in the python
  API.  This uses the python `del` keyword, similar to a native python
  list.  Similar to the existing `IRModule.__getitem__`, this can be
  called with either a `GlobalVar` or a python string.

* `IRModule.__contains__`: Check if a function is in the module.  This
  allows the pythone keyword `in` to check if a module contains a
  specific function.  Similar to the existing `IRModule.__getitem__`,
  this can be called either with a `GlobalVar` (`if gvar in mod`) or
  with a python string (`if "function_name" in mod`).

* [Unity][CodeGen] RunCodegen based on externally-exposed functions

Prior to this commit, `relax.transform.RunCodegen` required a list of
entry functions for a module, defaulting to `"main"` if not specified.
The list of entry functions is duplicate information that could be
inferred from the module, and should not be required from the user.
This commit updates `RunCodegen` to treat all externally-exposed
functions as entry points, in the same manner as
`DeadCodeElimination`.

For backwards compatibility, the `entry_functions` argument is still
accepted, and is used to augment the list of externally-exposed
functions.
2024-01-29 18:51:34 -08:00
Eric Lunderberg 2c49e01a0a [Unity][Transform] Implement relax.transform.ReorderTakeAfterMatmul (#16315)
If `R.matmul(x, R.take(weights, indices))` occurs, with `R.take`
selecting along the output feature dimension, it can be
rearranged to `R.take(R.matmul(x, weights), indices)`.
2024-01-23 16:43:08 -06:00
Eric Lunderberg 030ca4a74a [Unity][Transform] Implement relax.transform.ExpandMatmulOfSum (#16313)
An optimization pass that rewrites `x*(A+B)` into `x*A + x*B`, where
`x`, `A`, and `B` are relax tensors.
2024-01-23 10:18:29 -06:00
Steven S. Lyubomirsky a763b22119 [Unity][Transform] Replace eligible operators with in-place versions in dataflow blocks (#16129)
* Implement basic analyses

* Fix typo

* Add tests for analyses

* Include in-place analysis

* Return the lists instead

* Update python binding

* No need to assume *pure* functions capture all values ever passed to them. Also use pointers instead of non-const refs

* Improve handling of tuples in mystery call case

* Corrections to inplace checking

* Add test case for mystery value

* typo

* Add inplace test case, correct minor issues

* Consider also using larger tensors to store smaller ones

* Check call args against any possible target sinfo, also check tensor sinfo dtype

* Handle output vars and tuple get item

* Add legalization for in-place functions

* No need to update the NoAlias attribute, actually

* Fix TIR transformation, add tests for inline transformation

* Only find candidates from supported ops and list _all_ feasible argument indices

* Implement basic transformation pass

* Use a module pass so wider changes are visible, reorganize

* Have an end-to-end test case for the in-place transformation

* Rebase fixes and use GetBoundValue instead of reimplementing it

* Let's just use 'inplace' everywhere

* Reorganize code and add more documentation

* Include proper bounds check

* Trailing whitespace

* Need a trailing newline

* Remove unused imports

* Add docstrings for exposed inner functions

* Reformat docstrings to appease the linter

* C++ stylistic changes

* Treat args as mystery values by default, do not allow overwriting

* Formatting

* Clarify pass description

* Add check to ensure that testing functions are used only in a testing environment

* Improve size match check readability per review suggestions

* Improve the size match check per review suggestions (use PrimExprs)

* Treat non-dataflow vars as living past the end of the block in all cases

* Clarify notion of size in comment

* Remove commented-out code

* Assume any op that returns a tuple is returning a fresh one (exceptions can be noted later)

* Add full structural equality check in large test case

* Fix parser roundtripping bug with call_tir_inplace

* Refactor tests to ensure maps are nonempty

* Use .empty() where it's more reasonable

* linting changes

* Flipped the check by accident

* Remove debug print

* Factor out data structure for representing matches and match opportunities

* Style fix

* Use the analyzer to handle dynamic cases too

* Whitespace

* Use BlockBuilder APIs more to avoid re-normalizing

* Check for expired vars at start of loop so that the use of continue does not skip that step

---------

Co-authored-by: Eric Lunderberg <elunderberg@octoml.ai>
2024-01-17 17:05:54 -05:00
Eric Lunderberg 4c7c010513 [Unity][Transform] Implement relax.transform.AdjustMatmulOrder (#16314)
* [Unity][Analysis] Add utility for collecting compile-time bindings

Whether an optimizations should be performed may depend on when the
variables in an expression are known.

For example, consider a LoRA-adjusted model, with base weights `W` of
shape `[m,n]`, LoRA components `A` and `B` with shapes `[r,n]` and
`[m,r]` respectively, and activations `x` with shape `[n,1]`.  The
LoRA-adjusted matmul could be computed either as `(W + B*A)*x` or as
`(W*x + B*(A*x))`.

If `A` and `B` are provided at run-time, then computing `(W +
B*(A*x))` requires significantly fewer computations.

* `(W + B*A)*x`: `m*n*(2*r + 3)` operations
  1. `B*A`: `2*m*n*r` operations using a naive matmul
  2. Adding `W` to (1): `m*n` operations
  3. Multiplying `x` by (2): `2*m*n` operations

* `(W*x + B*(A*x))`: (2*m*n + r*(2*n + 2*m + 1))
  1. `W*x`: `2*m*n` operations
  2. `A*x`: `2*r*n` operations
  3. Multiplying `B` by (2): `2*m*r` operations
  4. Adding (1) and (3)`: `m` operations

However, if `A` and `B` are known at compile-time, then computing `(W
+ B*A)*x` groups all compile-time values together, allowing them to be
computed earlier (i.e. using `LiftTransformParams`)

* `(W + B*A)*x`: `2*m*n` operations
  1. `B*A`: 0 operations, computed at compile-time
  2. Adding `W` to (1): 0 operations, computed at compile-time
  3. Multiplying `x` by (2): `2*m*n` operations

Since the choice of optimized expression depends on which parameters
can be computed at compile-time, it is useful to have a utility that
identifies values that can be computed at compile-time.

* [Unity] QoL improvements for Dataflow matching

- Update the zero-parameter `WildcardPattern` constructor to produce a
  valid instance.  Previously, the zero-parameter constructor produced
  a null instance of `WildcardPattern`, which resulted in an error
  when used.  The `WildcardPattern` was expected to be constructed
  through the `Wildcard` function instead.  Since all other
  `DFPattern` child classes could be constructed explicitly, this
  could lead to unexpected outcomes.

- Check for `pattern.defined()` when performing a pattern-match.  If
  a null instance of a pattern is provided, this gives an error
  message with more context than the one raised by `DFPatternFunctor`.

- Expose `RewriteCall` for use in C++.  Previously, it had only been
  exposed through the FFI registry, and had no declaration in a header
  file.

* [Unity][Transform] Implement relax.transform.AdjustMatmulOrder

Reorder `x*(A*B)` to `(x*A)*B`.  Intended for optimization of LoRA
models, for which `(x*A)*B` has a much smaller memory footprint.

* Fix copy-paste error

* Check for re-orderings from the LHS, skip if cannot prove a benefit
2024-01-12 12:43:44 +08:00
Eric Lunderberg d88cc4267d [Unity][Transform] Implement UpdateParamStructInfo (#16305)
* [Unity][Transform] Implement UpdateParamStructInfo

Provide a convenience method to update parameter struct info,
propagating any changes to internal bindings and return type.

* lint fix

* Update implementation to update params in relax::Function mutator
2024-01-04 11:02:06 -06:00
Steven S. Lyubomirsky fe89ccc360 [Unity][Transform] Pass for automatically extracting DataflowBlocks (#16204)
* Implement a pass that extracts dataflow blocks from consecutive pure operations in binding blocks. Also contains bugfixes for canonicalize bindings

* Trailing whitespace

* current_block_ in CanonicalizeBindings should be optional, also lets us get rid of inside_dataflow_

* Add check that current_block_ is not set before we update it

* Also reset current_block_ for nested SeqExprs (like in If branches)

* Rename pass to ConvertToDataflow, reduce default min size to 2

* Handle case of dataflow bindings coming *after* a dataflow block

* Add additional test cases

* Add test cases for pure and impure inner and outer functions

* Add more non-call test cases

* Rebase fixes

---------

Co-authored-by: Eric Lunderberg <elunderberg@octoml.ai>
2023-12-13 17:44:10 -05:00
Eric Lunderberg 58e622b74d [Unity][Transform] Implement Relax function inlining (#16194)
* [Unity][Transform] Implement Relax function inlining

This commit adds the ability to inline one Relax function into
another.  This is provided with two APIs, one which allows explicit
specification of the functions to be inlined, and one which inlines
every private Relax function in an `IRModule`.  Function inlining with
explicit replacements is intended for use by an end-user when building
a model function (e.g. inlining of a rotary embedding), and the second
is intended for use as part of a generic optimization pipeline.

* lint fix

* Use DetectRecursion from relax/analysis.h

* Added test case for error on mutually-recursive functions
2023-12-09 12:25:13 -06:00
Eric Lunderberg fc324d0f2c [Unity][Transform] Implement RemoveUnusedParameters (#16116)
* [Unity] Implement RemoveUnusedParameters transform

Currently, the `FuseOps` and `FuseTIR` passes have a large amount of
added complexity to identify and handle partial use of tuple
arguments.  The handling partial use of tuples could be significantly
simpler if performed in multiple steps.

1. Perform `FuseOps`.  Any tuple variables that are used by the fused
   function are passed as-is.

2. Expand any parameters that are passed as a tuple.  Any unused
   tensors that were included in a partially-used tuple will be
   converted to unused parameters.

3. Remove any unused parameters.  Any unused tensors that were
   included in a partially-used tuple will be removed in this
   step.

4. Perform `FuseTIR`.  No checking for tuple arguments, either partial
   or full, is required at this step.

This PR implements `relax.transform.RemoveUnusedParameters`, which is
step (3) in this process.

* Update based on review comments
2023-12-01 15:47:31 -06:00
Eric Lunderberg fe9d2fe57d [Unity][Transform] Implement ExpandTupleArguments (#16115)
[Unity] Implement ExpandTupleArguments transform

Currently, the `FuseOps` and `FuseTIR` passes have a large amount of
added complexity to identify and handle partial use of tuple
arguments.  The handling partial use of tuples could be significantly
simpler if performed in multiple steps.

1. Perform `FuseOps`.  Any tuple variables that are used by the fused
   function are passed as-is.

2. Expand any parameters that are passed as a tuple.  Any unused
   tensors that were included in a partially-used tuple will be
   converted to unused parameters.

3. Remove any unused parameters.  Any unused tensors that were
   included in a partially-used tuple will be removed in this
   step.

4. Perform `FuseTIR`.  No checking for tuple arguments, either partial
   or full, is required at this step.

This PR implements `relax.transform.ExpandTupleArguments`, which is
step (2) in this process.
2023-12-01 08:21:04 -06:00
Eric Lunderberg d52a9bf388 [Unity][Transform] Implement RemoveUnusedOutputs (#16117)
[Unity] Implement RemoveUnusedOutputs transform

This commit implements `relax.transform.RemoveUnusedOutputs`, an
extension of the current `DeadCodeElimination` pass.  If an internal
callee produces multiple outputs, but only some of those outputs are
used, the callee can be rewritten to only produce the outputs that are
used.  This is intended to allow more aggressive DCE in the callee, as
reducing the set of outputs can result in intermediate computations
becoming unused.
2023-11-30 08:18:55 -06:00
Yixin Dong 2dcb8716e8 [Unity][BlockBuilder] Depracate BlockBuilder.get() and change it to BlockBuilder.finalize() (#16090)
* 1108

* fix ci

* 1109

* finished

* fix ci
2023-11-28 10:41:46 +08:00
Archermmt 29450b927e [Unity][MSC] Enable add attributes while fuse ops (#16128)
* enable attrs_getter

* update test case for attrs_getter

* add name checker for test tensorrt

* remove pattern.py

* add unique name for tuple

* change attrs_getter argument

* change attrs getter signature
2023-11-20 18:45:25 +09:00