This is an automated email from the ASF dual-hosted git repository.

Seven-Streams pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tvm-tirx.git


The following commit(s) were added to refs/heads/main by this push:
     new 640416119 [DOCS] Introduce Symbolic Integer Analysis (#57)
640416119 is described below

commit 6404161197ee4ad59f8598f0f96be7d7a5bff481
Author: Shushi Hong <[email protected]>
AuthorDate: Tue Oct 27 15:35:43 2026 -0400

    [DOCS] Introduce Symbolic Integer Analysis (#57)
    
    Add a brief **Symbolic Integer Analysis** overview under Compiler
    Internals. Describe its role in reasoning about shapes, loop bounds, and
    indices, introduce `sym.Analyzer`, and link to the current API
    reference. The overview stays concise while the analysis infrastructure
    and its APIs are under active development.
---
 docs/compiler/symbolic_integer_analysis.rst | 239 ++++++++++++++++++++++++++++
 docs/index.rst                              |   7 +
 2 files changed, 246 insertions(+)

diff --git a/docs/compiler/symbolic_integer_analysis.rst 
b/docs/compiler/symbolic_integer_analysis.rst
new file mode 100644
index 000000000..8d65c956f
--- /dev/null
+++ b/docs/compiler/symbolic_integer_analysis.rst
@@ -0,0 +1,239 @@
+..  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.
+
+Symbolic Integer Analysis
+=========================
+
+In this chapter, we will introduce symbolic integer analysis for tensor
+shapes, loop bounds, and element indices. A pass that combines four scalar
+accesses into one vector access needs to preserve their positions and
+establish that the whole group is within the tensor. The length may only
+be known at runtime, so these decisions require reasoning about symbolic
+expressions. We will start from a loop's known range, then examine grouped
+indices and a neighboring-element access.
+
+The Analyzer
+------------
+
+:class:`sym.Analyzer <tvm_tirx.sym.Analyzer>` answers queries about integer
+IR expressions. It combines algebraic rules with facts supplied by a pass,
+such as a loop variable's range. The same analyzer can use those facts
+across several queries:
+
+.. list-table::
+   :header-rows: 1
+   :widths: 32 28 40
+
+   * - Query
+     - Arguments
+     - Result
+   * - ``simplify(expr)``
+     - An IR expression.
+     - An equivalent IR expression in a simpler form.
+   * - ``int_set(expr)``
+     - An integer IR expression.
+     - A ``sym.IntSet`` covering its possible values, including symbolic 
bounds.
+   * - ``const_int_bound(expr)``
+     - An integer IR expression.
+     - A ``sym.ConstIntBound`` with inclusive numeric bounds.
+   * - ``modular_set(expr)``
+     - An integer IR expression.
+     - A ``sym.ModularSet`` describing divisibility and remainders.
+   * - ``can_prove(expr)``
+     - A boolean IR expression.
+     - ``True`` if the condition is established from the known facts.
+   * - ``can_prove_equal(lhs, rhs)``
+     - Two integer IR expressions.
+     - ``True`` if their values are established to be equal.
+
+These calls show the required arguments. The expressions describe
+calculations in the program, and the analyzer uses its known facts to
+reason about their runtime values.
+
+Facts from the Program
+----------------------
+
+The analyzer needs facts from the point in the program where a rewrite
+would occur. In a loop over a contiguous tensor of symbolic length ``n``,
+the index ``i`` satisfies ``0 <= i < n``. We can represent the length and
+index directly with integer IR variables:
+
+.. code-block:: python
+
+   from tvm_tirx import ir, sym
+
+   n = ir.Var("n", "int32")
+   i = ir.Var("i", "int32")
+   analyzer = sym.Analyzer()
+
+The loop bounds belong to the loop statement, while the variable ``i``
+records a name and type. A query on ``i`` therefore does not automatically
+include those bounds. The pass supplies them through a ``RangeConstraint``;
+a ``ConstraintContext`` collects the facts for the current program point:
+
+.. code-block:: python
+
+   range_fact = sym.RangeConstraint(i, ir.Range(0, n))
+   context = sym.ConstraintContext()
+   context.append(range_fact)
+   analyzer.sync_constraint_context(context)
+
+The range starts at zero and has extent ``n``:
+
+.. code-block:: text
+
+   range_fact: sym.RangeConstraint
+   ├── var → ir.Var                     i
+   └── range: ir.Range
+       ├── begin: ir.IntImm              0
+       └── extent: ir.Var                n
+
+``sync_constraint_context`` makes these facts available to subsequent
+queries. The analyzer captures the context at synchronization, so later
+additions need another synchronization. A pass moving to another part
+of the program must supply the context valid there.
+
+Simplifying Index Expressions
+-----------------------------
+
+A vectorization pass can split the loop index ``i`` into a group start
+and a lane within a group of four. The address calculation may later
+recombine these parts, leaving division and remainder operations that can
+be removed. The group starts at ``(i // 4) * 4``, and ``i % 4`` gives its
+lane. For example, index 6 belongs to the group starting at 4 and occupies
+lane 2. The analyzer can simplify the recombined expression:
+
+.. code-block:: python
+
+   group_start = (i // 4) * 4
+   lane = i % 4
+   simplified = analyzer.simplify(group_start + lane)
+   print(simplified)
+
+The output is:
+
+.. code-block:: text
+
+   i
+
+``simplified`` is the IR expression a pass can use to replace the longer
+index calculation.
+
+Bounds and Divisibility
+-----------------------
+
+The loop range guarantees that ``A[i]`` is in bounds. A computation that
+also reads ``A[i + 1]`` needs to establish a bound for that new index.
+``int_set`` can bound its possible values before the pass decides whether
+the access needs a guard:
+
+.. code-block:: python
+
+   next_index = i + 1
+   possible_values = analyzer.int_set(next_index)
+   print(analyzer.simplify(possible_values.min_value))
+   print(analyzer.simplify(possible_values.max_value))
+
+The output is:
+
+.. code-block:: text
+
+   1
+   n
+
+For this expression, ``int_set`` returns a ``sym.IntervalSet``. Its
+``min_value`` and ``max_value`` fields are integer IR expressions, so
+the endpoints can depend on ``n``. The interval is inclusive: ``i + 1``
+can reach ``n`` on the last iteration. This matters because the final
+valid tensor index is ``n - 1``.
+
+The grouping calculation gives another bounds query: the lane must select
+one of the group's four positions. Its bounds are numeric, so
+``const_int_bound`` can report them directly:
+
+.. code-block:: python
+
+   lane_bounds = analyzer.const_int_bound(lane)
+   print(lane_bounds.min_value, lane_bounds.max_value)
+
+The output is:
+
+.. code-block:: text
+
+   0 3
+
+These endpoints are also inclusive, describing the four lane positions.
+Bounds cover every possible value; for more complex expressions, an
+inferred interval may also contain values that never occur.
+
+The start offset also matters for a vector access. A pass can use
+``modular_set`` to check whether every group starts on a multiple of four:
+
+.. code-block:: python
+
+   multiples = analyzer.modular_set(group_start)
+   print(multiples.coeff, multiples.base)
+
+The output is:
+
+.. code-block:: text
+
+   4 0
+
+``coeff`` and ``base`` describe values of the form ``coeff*k + base``
+for integer ``k``. Every group therefore starts on a four-element boundary.
+A vectorization pass can use this offset information together with the
+base-address alignment and access bounds.
+
+Proving Conditions
+------------------
+
+A compiler pass often needs a yes-or-no answer before it removes a check
+or replaces an index. A proof query asks whether the required condition
+holds for every value allowed by the known facts. The following calls
+check the original index, the neighboring index, and the regrouped index:
+
+.. code-block:: python
+
+   print(analyzer.can_prove(i < n))
+   print(analyzer.can_prove(next_index < n))
+   print(analyzer.can_prove_equal(group_start + lane, i))
+
+The output is:
+
+.. code-block:: text
+
+   True
+   False
+   True
+
+The known range proves ``i < n``, so a redundant check of this condition
+inside the loop can be removed. The neighboring index can reach ``n``,
+so ``i + 1 < n`` cannot be established for every iteration. That access
+needs a guard or an iteration range that excludes the last element.
+
+In general, ``False`` means that the analyzer did not prove a condition;
+it does not prove the opposite condition. A pass cannot use that result
+to justify removing a bounds check.
+
+``can_prove_equal`` compares expression values. Here, its ``True`` result
+confirms that a pass can replace ``group_start + lane`` with ``i`` while
+preserving the element index, even though their IR structures differ.
+
+The analysis infrastructure and its APIs are under active development.
+The :doc:`tvm_tirx.sym </reference/python/sym>` reference describes the
+current interfaces.
diff --git a/docs/index.rst b/docs/index.rst
index cacf5409d..5bc68c9f0 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -40,6 +40,13 @@ Table of Contents
    ir/functions_and_modules
    ir/printing_and_parsing
 
+.. toctree::
+   :maxdepth: 1
+   :caption: Compiler Internals
+   :titlesonly:
+
+   compiler/symbolic_integer_analysis
+
 .. toctree::
    :maxdepth: 1
    :caption: Reference

Reply via email to