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

tqchen 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 7b2bc5834 [SYM] Document Analyzer contracts and narrow internal DLL 
exports (#73)
7b2bc5834 is described below

commit 7b2bc5834115e076a3d3106a781211038d7b6f3d
Author: Tianqi Chen <[email protected]>
AuthorDate: Sun Oct 25 14:48:09 2026 -0400

    [SYM] Document Analyzer contracts and narrow internal DLL exports (#73)
    
    Analyzer clients need explicit contracts for synchronized premises,
    shared snapshot nodes, conservative proofs, and solver diagnostics.
    Document the public Analyzer surface and context lifetimes, correct
    simplification and counterexample-query descriptions, and explain
    private helper roles.
    
    Keep compiler-local backend reset and ingestion methods out of the DLL
    interface while preserving exports needed by inline object destruction
    and scope guards. Clone behavior remains unchanged.
---
 include/tvm/sym/analyzer.h   | 410 +++++++++++++++++++++++++++----------------
 include/tvm/sym/constraint.h |  45 +++--
 src/sym/z3_prover.cc         |   8 +-
 3 files changed, 294 insertions(+), 169 deletions(-)

diff --git a/include/tvm/sym/analyzer.h b/include/tvm/sym/analyzer.h
index bc1360606..29f526c15 100644
--- a/include/tvm/sym/analyzer.h
+++ b/include/tvm/sym/analyzer.h
@@ -61,6 +61,7 @@ namespace detail {
 class TempConstraintScope;
 }  // namespace detail
 
+/*! \brief Integer division semantics used by symbolic analysis. */
 enum DivMode {
   /*! \brief Truncated division. */
   kTruncDiv,
@@ -69,14 +70,14 @@ enum DivMode {
 };
 
 /*!
- * \brief The strength used in top-level condition proves
+ * \brief The strength used for top-level condition proofs.
  * \note The higher, the more time consuming it can be.
  *
  * Do not use level beyond kDefault in internal recursive rewriting in sym
  * analysis and only use it at top-level simplification to avoid speed issues.
  */
 enum class ProofStrength : int {
-  /*! \brief default strength, can be used in. */
+  /*! \brief Default simplification-based proof, suitable for recursive 
analysis. */
   kDefault = 0,
   /*!
    * \brief Prove using symbolic bound analysis
@@ -85,16 +86,18 @@ enum class ProofStrength : int {
 };
 
 /*!
- * \brief Constant integer up and lower bound(inclusive).
- *  Useful for value bound analysis.
+ * \brief Inclusive constant integer bounds, representing [min_value, 
max_value].
  *
- *  set = [min_value, max_value]
+ * The infinity sentinels represent unbounded endpoints, not finite integer 
values.
  */
 class ConstIntBoundObj : public ffi::Object {
  public:
+  /*! \brief Inclusive lower endpoint, or kNegInf when unbounded. */
   int64_t min_value;
+  /*! \brief Inclusive upper endpoint, or kPosInf when unbounded. */
   int64_t max_value;
 
+  /*! \brief Register the fields exposed through FFI reflection. */
   static void RegisterReflection() {
     namespace refl = tvm::ffi::reflection;
     refl::ObjectDef<ConstIntBoundObj>()
@@ -106,28 +109,27 @@ class ConstIntBoundObj : public ffi::Object {
   static const constexpr int64_t kPosInf = std::numeric_limits<int64_t>::max();
   /*!
    * \brief Number to represent -inf
-   * \note We can make use the of fact that -kPosInf == kNegInf in the project.
+   * \note The sentinels satisfy -kPosInf == kNegInf.
    */
   static const constexpr int64_t kNegInf = -kPosInf;
 
+  /*! \brief Compare and hash these value objects structurally. */
   static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind = 
kTVMFFISEqHashKindTreeNode;
   TVM_FFI_DECLARE_OBJECT_INFO_FINAL("sym.ConstIntBound", ConstIntBoundObj, 
ffi::Object);
 };
 
 /*!
- * \brief reference class to ConstIntBoundObj
+ * \brief Managed reference to ConstIntBoundObj.
  * \sa ConstIntBoundObj
  */
 class ConstIntBound : public ffi::ObjectRef {
  public:
-  /*!
-   * \brief constructor by fields.
-   * \param min_value The mininum value.
-   * \param max_value The maximum value.
-   */
+  /*! \brief Construct inclusive bounds; endpoints may use the infinity 
sentinels. */
   TVM_TIRX_DLL ConstIntBound(int64_t min_value, int64_t max_value);
 
+  /*! \brief Sentinel for an unbounded upper endpoint. */
   static const constexpr int64_t kPosInf = ConstIntBoundObj::kPosInf;
+  /*! \brief Sentinel for an unbounded lower endpoint. */
   static const constexpr int64_t kNegInf = ConstIntBoundObj::kNegInf;
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(ConstIntBound, ffi::ObjectRef, 
ConstIntBoundObj);
 };
@@ -137,64 +139,69 @@ class ConstIntBound : public ffi::ObjectRef {
  */
 class ConstIntBoundAnalyzer {
  public:
+  /*! \brief Query results keyed by expression object identity. */
   using BoundMapType =
       std::unordered_map<PrimExpr, ConstIntBound, ffi::ObjectPtrHash, 
ffi::ObjectPtrEqual>;
   /*!
-   * \brief analyze the expr
-   * \param expr The expression of interest.
-   * \return the result of the analysis.
+   * \brief Compute conservative constant bounds under the current premises.
+   * \param expr The integer expression to analyze.
+   * \return Inclusive bounds; unproved endpoints use the infinity sentinels.
    */
   TVM_TIRX_DLL ConstIntBound operator()(const PrimExpr& expr) const;
 
   /*!
-   * \brief analyze the expr with the intermediate memorized to avoid 
redundant computation
-   * \param expr The expression of interest.
-   * \param bound Output map, cleared on entry so results cannot cross context 
epochs
-   * \return the result of the analysis.
+   * \brief Compute bounds and optionally collect intermediate query results.
+   * \param expr The integer expression to analyze.
+   * \param bound Optional output map, cleared on entry and borrowed only for 
this call.
+   * Its results describe the current premises and are not updated by later 
synchronization.
+   * \return Inclusive conservative bounds for expr.
    */
   TVM_TIRX_DLL ConstIntBound operator()(const PrimExpr& expr, BoundMapType* 
bound);
 
   /*!
-   * \brief Check if a variable is bound to a range.
+   * \brief Check whether a binding or recognized predicate supplies bounds 
for a variable.
    * \param var The variable.
-   * \return Whether the variable is bound to a range.
+   * \return True when such information is recorded, even if its bounds are 
unbounded.
    */
   TVM_TIRX_DLL bool IsBound(const Var& var) const;
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const Range& range);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Record a half-open variable range from the accepted premise prefix.
+  void IngestBinding(const Var& var, const Range& range);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
+  // Borrow the owning analyzer for cross-backend queries.
   explicit ConstIntBoundAnalyzer(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~ConstIntBoundAnalyzer();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const ConstIntBoundAnalyzer& other);
   struct Entry;
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   std::unique_ptr<Impl> impl_;
 };
 
 /*!
- * \brief Range of a linear integer function.
- *  Use to do specify the possible index values.
- *
- *  set = { coeff * x + base | x in Z }
- *
- *  When coeff != 0, it can also be written as
- *  set = { n | n % coeff == base }
+ * \brief Integer congruence class {coeff * x + base | x in Z}.
  *
- *  This is useful to decide if the index is dividable by certain value.
- *  For example, if index = 0 + 4 x, then we know it can be divided by 4.
+ * A zero coefficient represents the singleton {base}; a coefficient of one
+ * represents all integers. This information can establish divisibility, for
+ * example every element of {4 * x | x in Z} is divisible by four.
  */
 class ModularSetObj : public ffi::Object {
  public:
-  /*! \brief linear co-efficient */
+  /*! \brief Coefficient of the arbitrary integer multiplier. */
   int64_t coeff;
-  /*! \brief The base */
+  /*! \brief Constant offset of the congruence class. */
   int64_t base;
 
+  /*! \brief Register the fields exposed through FFI reflection. */
   static void RegisterReflection() {
     namespace refl = tvm::ffi::reflection;
     refl::ObjectDef<ModularSetObj>()
@@ -202,16 +209,18 @@ class ModularSetObj : public ffi::Object {
         .def_ro("base", &ModularSetObj::base);
   }
 
+  /*! \brief Compare and hash these value objects structurally. */
   static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind = 
kTVMFFISEqHashKindTreeNode;
   TVM_FFI_DECLARE_OBJECT_INFO_FINAL("sym.ModularSet", ModularSetObj, 
ffi::Object);
 };
 
 /*!
- * \brief reference of ModularSetObj
+ * \brief Managed reference to ModularSetObj.
  * \sa ModularSetObj
  */
 class ModularSet : public ffi::ObjectRef {
  public:
+  /*! \brief Store coeff and base as supplied, without normalization. */
   TVM_TIRX_DLL ModularSet(int64_t coeff, int64_t base);
 
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(ModularSet, ffi::ObjectRef, 
ModularSetObj);
@@ -223,23 +232,29 @@ class ModularSet : public ffi::ObjectRef {
 class ModularSetAnalyzer {
  public:
   /*!
-   * \brief analyze the expr
-   * \param expr The expression of interest.
-   * \return the result of the analysis.
+   * \brief Compute conservative congruence information under the current 
premises.
+   * \param expr The integer expression to analyze.
+   * \return A congruence class containing every possible value of expr.
    */
   TVM_TIRX_DLL ModularSet operator()(const PrimExpr& expr);
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
+  // Borrow the owning analyzer for cross-backend queries.
   explicit ModularSetAnalyzer(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~ModularSetAnalyzer();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const ModularSetAnalyzer& other);
   struct Entry;
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   std::unique_ptr<Impl> impl_;
 };
 
@@ -249,19 +264,23 @@ class ModularSetAnalyzer {
 class RewriteSimplifier {
  public:
   /*!
-   * \brief analyze the expr
-   * \param expr The expression of interest.
-   * \return the result of the analysis.
+   * \brief Simplify an expression under the current premises.
+   * \param expr The expression to simplify.
+   * \return An equivalent expression under those premises.
    */
   TVM_TIRX_DLL PrimExpr operator()(const PrimExpr& expr);
 
-  /*! \brief Return the statistics counters */
+  /*!
+   * \brief Read cumulative rewrite statistics.
+   * \return A snapshot of the current counters.
+   */
   TVM_TIRX_DLL ffi::ObjectRef GetStatsCounters() const;
 
-  /*! \brief Reset the statistics counters */
+  /*! \brief Clear cumulative rewrite counters without changing facts or the 
rewrite limit. */
   TVM_TIRX_DLL void ResetStatsCounters();
 
-  /*! \brief Set the maximum allowed number of rewrite steps
+  /*!
+   * \brief Set the maximum allowed cumulative number of successful rewrites.
    *
    * By default, the simplifier may perform as many steps as are
    * required.  If a positive limit is set, then the simplifier will
@@ -271,23 +290,31 @@ class RewriteSimplifier {
    * Note: To maintain accurate usage counters, `Analyzer` instances
    * should be re-used wherever possible.  For example, TIR
    * transformations should declare a single `Analyzer` that is used
-   * throughout the pass.  Internal helper functions that only borrow
-   * the analyzer temporarily may receive the underlying `AnalyzerObj*`
-   * from their calling scope.
+   * throughout the pass. Internal helpers may borrow its `AnalyzerObj*`.
+   *
+   * The limit applies to the cumulative counter, not separately to each query.
+   * ResetStatsCounters starts a new accounting interval.
+   * \param maximum Positive rewrite limit, or a nonpositive value for no 
limit.
    */
   TVM_TIRX_DLL void SetMaximumRewriteSteps(int64_t maximum);
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
   friend class CanonicalSimplifier;
+  // Borrow the owning analyzer for cross-backend queries.
   explicit RewriteSimplifier(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~RewriteSimplifier();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const RewriteSimplifier& other);
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   ffi::ObjectPtr<Impl> impl_;
 };
 
@@ -297,43 +324,69 @@ class RewriteSimplifier {
 class CanonicalSimplifier {
  public:
   /*!
-   * \brief analyze the expr
-   * \param expr The expression of interest.
-   * \return the result of the analysis.
+   * \brief Simplify an expression under the current premises.
+   * \param expr The expression to simplify.
+   * \return An equivalent expression under those premises.
    */
   TVM_TIRX_DLL PrimExpr operator()(const PrimExpr& expr);
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Borrow the owning analyzer for cross-backend queries.
   explicit CanonicalSimplifier(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~CanonicalSimplifier();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const CanonicalSimplifier& other);
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   ffi::ObjectPtr<Impl> impl_;
 };
 
-/*! \brief Structure for representing result of known
+/*!
+ * \brief Possible orderings of two expressions, represented as a bit set.
  *
- * Values are assigned to allow these flags to be used in bitwise
- * operations.
+ * EQ, LT, and GT are independent bits. Intersection combines facts that all
+ * hold; union combines alternative possibilities. Zero indicates 
inconsistency.
  */
 enum class CompareResult : int {
+  /*! \brief No ordering is possible under the known facts. */
   kInconsistent = 0,
+  /*! \brief Equal. */
   kEQ = 1,
+  /*! \brief Strictly less. */
   kLT = 2,
+  /*! \brief Less than or equal. */
   kLE = 3,
+  /*! \brief Strictly greater. */
   kGT = 4,
+  /*! \brief Greater than or equal. */
   kGE = 5,
+  /*! \brief Unequal. */
   kNE = 6,
+  /*! \brief Any ordering is possible. */
   kUnknown = 7
 };
 
+/*!
+ * \brief Intersect the possible orderings.
+ * \param lhs First set of orderings.
+ * \param rhs Second set of orderings.
+ * \return The combined set of orderings.
+ */
 inline constexpr CompareResult operator&(CompareResult lhs, CompareResult rhs) 
{
   return CompareResult(static_cast<int>(lhs) & static_cast<int>(rhs));
 }
+/*!
+ * \brief Unite the possible orderings.
+ * \param lhs First set of orderings.
+ * \param rhs Second set of orderings.
+ * \return The combined set of orderings.
+ */
 inline constexpr CompareResult operator|(CompareResult lhs, CompareResult rhs) 
{
   return CompareResult(static_cast<int>(lhs) | static_cast<int>(rhs));
 }
@@ -345,7 +398,8 @@ inline constexpr CompareResult operator|(CompareResult lhs, 
CompareResult rhs) {
  */
 class KnownComparisonAnalyzer {
  public:
-  /* \brief Using previously specified knowns, compare the expressions provided
+  /*!
+   * \brief Compare expressions using recorded relations and constant offsets.
    *
    * \param lhs The left-hand side of the comparison
    *
@@ -360,15 +414,22 @@ class KnownComparisonAnalyzer {
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const Range& range);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Record a half-open variable range from the accepted premise prefix.
+  void IngestBinding(const Var& var, const Range& range);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
+  // Borrow the owning analyzer for cross-backend queries.
   explicit KnownComparisonAnalyzer(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~KnownComparisonAnalyzer();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const KnownComparisonAnalyzer& other);
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   std::unique_ptr<Impl> impl_;
 };
 
@@ -379,18 +440,17 @@ class IntSetAnalyzer {
  public:
   /*!
    * \brief Find a symbolic integer set that contains all possible values of
-   *        expr given the domain of each variables.
+   *        expr given the supplied variable domains.
    *
    * \param expr The expression of interest.
-   * \param dom_map The domain map to indicate which variable to relax.
+   * \param dom_map The variable domains to relax; variables absent from the 
map remain symbolic.
    * \return the result of the analysis.
    */
   TVM_TIRX_DLL IntSet operator()(const PrimExpr& expr, const ffi::Map<Var, 
IntSet>& dom_map);
 
   /*!
    * \brief Find a symbolic integer set that contains all possible
-   *        values of expr given the domain of each variables, using
-   *        the domain map defined by bound variables.
+   *        values of expr using current bindings, ranges, and recognized 
predicates.
    *
    * \param expr The expression of interest.
    * \return the result of the analysis.
@@ -399,109 +459,130 @@ class IntSetAnalyzer {
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const Range& range);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear context-derived facts before replay; retain query settings and 
diagnostics.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Record a half-open variable range from the accepted premise prefix.
+  void IngestBinding(const Var& var, const Range& range);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
+  // Borrow the owning analyzer for cross-backend queries.
   explicit IntSetAnalyzer(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~IntSetAnalyzer();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const IntSetAnalyzer& other);
   class Impl;
-  /*! \brief Internal impl */
+  // Owned backend state; its definition stays inside the compiler library.
   Impl* impl_;
 };
 
+/*!
+ * \brief Optional Z3-backed prover over the analyzer's accepted premises.
+ *
+ * Diagnostic and enumeration queries may propagate translation or solver 
errors.
+ * Their temporary assertions do not change the accepted premise environment.
+ */
 class Z3Prover {
  public:
   /*!
-   * \brief Whether the Z3 backend is compiled into this build (USE_Z3=ON).
+   * \brief Whether the Z3 backend is compiled into this build 
(TVM_TIRX_USE_Z3=ON).
    *
    * \return true if the real Z3 prover is available, false for the stub.
    */
   TVM_TIRX_DLL bool IsEnabled() const;
 
   /*!
-   * \brief Whether can we prove expr is always true.
-   *
-   * \param expr The expression.
-   * \return Whether we can prove it.
+   * \brief Attempt to prove that expr holds under the current premises.
+   * \param expr Boolean expression to prove.
+   * \return True only when proved; false for unsupported expressions, an 
unavailable
+   * backend, an inconclusive solver result, or a caught Z3 error. False is 
not a disproof.
    */
   TVM_TIRX_DLL bool CanProve(const PrimExpr& expr);
 
   /*!
    * \brief Get the SMTLIB2 representation of the current context.
    *
-   * \param expr The optional expression to check.
-   * \return The SMTLIB2 string.
+   * \param expr Optional boolean expression whose negation is added as a 
proof query.
+   * \return The SMTLIB2 string, or a comment indicating that Z3 is disabled.
    */
   TVM_TIRX_DLL ffi::String GetSMTLIB2(const ffi::Optional<PrimExpr> expr);
 
   /*!
    * \brief Get statistics about Z3 prover.
    *
-   * \return The statistics string.
+   * \return The statistics string, or a comment indicating that Z3 is 
disabled.
    */
   TVM_TIRX_DLL ffi::String GetStats();
 
   /*!
    * \brief Set timeout in milliseconds for Z3 prover.
    *
-   * \param timeout_ms The timeout in milliseconds.
+   * \param timeout_ms The timeout in milliseconds; zero disables the timeout. 
Ignored by the stub.
    */
   TVM_TIRX_DLL void SetTimeoutMs(unsigned timeout_ms);
 
   /*!
    * \brief Set resource limitation for Z3 prover.
    *
-   * \param rlimit the resource limitation.
+   * \param rlimit Z3 resource limit; zero disables it. Ignored by the stub.
    */
   TVM_TIRX_DLL void SetRLimit(unsigned rlimit);
 
   /*!
-   * \brief Get the Z3 model for the given expression if satisfiable.
+   * \brief Get a counterexample model for a boolean expression.
    *
-   * \param expr The expression to get the model for.
-   * \return The model as a string.
+   * \param expr Boolean expression whose negation is checked under the 
current premises.
+   * \return A model satisfying the negation, or an empty string if no model 
is found
+   * (including an unknown result). The stub returns a comment indicating Z3 
is disabled.
    */
   TVM_TIRX_DLL ffi::String GetModel(const PrimExpr& expr);
 
   /*!
    * \brief Count the number of integer values that satisfy the current 
constraints.
    *
-   * This method uses Z3's model enumeration to count how many distinct values 
of
-   * the given variable satisfy all current constraints.
+   * Enumerates distinct values until the limit, unsatisfiability, or an 
inconclusive
+   * result. The count may be partial; it is not a proof of the domain 
cardinality.
    *
    * \param var The variable to count satisfying values for.
-   * \param max_count Maximum number of solutions to enumerate.
-   * \param min_consecutive Minimum consecutive count requirement.
-   * \return The number of distinct values that satisfy the constraints, or a 
negative error code.
+   * \param max_count Maximum number of values to enumerate; nonpositive 
values enumerate none.
+   * \param min_consecutive Minimum size of each consecutive run in the 
enumerated values;
+   * nonpositive values disable this check. The check does not establish 
complete coverage.
+   * \return The enumerated count, -1 for an unsupported variable or disabled 
Z3, or -2
+   * if a nonempty enumerated run is shorter than min_consecutive. Errors may 
propagate.
    */
   TVM_TIRX_DLL int64_t CountSatisfyingValues(const Var& var, int64_t max_count 
= 2048,
                                              int64_t min_consecutive = 1);
 
  private:
   friend class AnalyzerObj;
-  TVM_TIRX_DLL void Reset();
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const PrimExpr& expr);
-  TVM_TIRX_DLL void IngestBinding(const Var& var, const Range& range);
-  TVM_TIRX_DLL void IngestPredicate(const PrimExpr& constraint);
+  // Clear facts, translations, and solver state; retain resource limits.
+  void Reset();
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
+  void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Record a half-open variable range from the accepted premise prefix.
+  void IngestBinding(const Var& var, const Range& range);
+  // Consume a predicate prepared against the preceding premise prefix.
+  void IngestPredicate(const PrimExpr& constraint);
   friend class Analyzer;
+  // Borrow the owning analyzer for cross-backend queries.
   explicit Z3Prover(AnalyzerObj* parent);
+  // Exported for destruction through the inline Analyzer object allocator.
   TVM_TIRX_DLL ~Z3Prover();
+  // Copy durable facts/settings into this backend without sharing mutable 
query state.
   void CopyFrom(const Z3Prover& other);
   class Impl;
   std::unique_ptr<Impl> impl_;
 };
 
 /*!
- * \brief Analyzer that contains bunch of sub-analyzers.
- *
- * Each sub-analyzer can make use of another sub-analyzer
- * by weak reference of this.
+ * \brief Coordinated symbolic analyses over an explicitly synchronized 
premise environment.
  *
- * NOTE for sub-analyzer developers:
- * If the analyzer uses memoization, we need to clear the internal
- * cache when information about a Var has been overridden.
+ * Queries may update caches, solver state, and statistics, but do not append
+ * persistent premises. Proof methods are conservative: false means not proved.
+ * Sub-analyzers borrow their owner and must not outlive it. This mutable 
object
+ * must not be queried or synchronized concurrently from multiple threads.
  */
 class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
  public:
@@ -519,53 +600,71 @@ class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
   KnownComparisonAnalyzer known_comparisons;
   /*! \brief sub-analyzer using Z3 */
   Z3Prover z3_prover;
-  /*! \brief constructor */
+  /*! \brief Construct an analyzer with no accepted premises and default query 
settings. */
   AnalyzerObj();
-  /*! \brief Synchronize all derived facts to the supplied premise environment.
-   * Unchanged positions are free; additive prefixes update incrementally and
-   * other transitions clear and replay. Do not mutate captured premises 
through aliases.
+  /*!
+   * \brief Synchronize all derived facts to the supplied premise environment.
+   *
+   * Unchanged positions need no replay; recognized additive prefixes update
+   * incrementally, and other transitions clear and replay all backends. Query
+   * settings and cumulative rewrite counters survive synchronization.
+   *
+   * The context must bind each Var identity at most once across value and 
range
+   * bindings. Unsupported or effectful premises may be ignored conservatively.
+   * Captured constraint and expression nodes must not be mutated through 
aliases.
+   * Appending to the caller's context after this call takes effect only after 
a
+   * later synchronization. Synchronization during a query or another 
synchronization
+   * is rejected. If ingestion throws, discard this analyzer: partially applied
+   * backend state is not rolled back.
+   *
+   * \param context Ordered premises to snapshot and accept.
+   * \throws ffi::Error If bindings repeat a Var identity, synchronization is
+   * reentrant, or an analyzer invariant fails. Backend ingestion errors may 
also propagate.
    */
   void SyncConstraintContext(const ConstraintContext& context);
-  /*! \brief Return an independently extensible snapshot of the accepted 
premises. */
+  /*!
+   * \brief Snapshot the accepted premise environment.
+   * \return A context that can be extended independently. Constraint and 
expression
+   * nodes are shared and must not be mutated through aliases. Appending to 
this
+   * context does not update the analyzer until SyncConstraintContext is 
called.
+   */
   ConstraintContext GetConstraintContext() const;
   /*!
-   * \brief Whether can we prove expr >= val.
-
-   *  Non-negative proof is very useful in integer analysis
-   *  to lower divisions and mods given difference in trunc and ceil mode.
+   * \brief Attempt to prove expr >= lower_bound.
+   *
+   * Bounds help distinguish truncating and floor division/remainder semantics.
    *
    * \param expr The expression.
    * \param lower_bound The lower bound.
-   * \return Whether we can prove it.
+   * \return True if proved; false if unknown or false.
    *
    * \note Analyzer will call into sub-analyzers to get the result.
    */
   bool CanProveGreaterEqual(const PrimExpr& expr, int64_t lower_bound);
   /*!
-   * \brief Whether can we prove expr < val.
-
-   *  Non-negative proof is very useful in integer analysis
-   *  to lower divisions and mods given difference in trunc and ceil mode.
+   * \brief Attempt to prove expr < upper_bound.
+   *
+   * Bounds help distinguish truncating and floor division/remainder semantics.
    *
    * \param expr The expression.
    * \param upper_bound The upper bound.
-   * \return Whether we can prove it.
+   * \return True if proved; false if unknown or false.
    *
    * \note Analyzer will call into sub-analyzers to get the result.
    */
   bool CanProveLess(const PrimExpr& expr, int64_t upper_bound);
   /*!
-   * \brief Whether can we prove lhs == rhs.
+   * \brief Attempt to prove lhs == rhs.
    *
    * \param lhs The input lhs.
    * \param rhs The input rhs.
-   * \return Whether we can prove lhs == rhs.
+   * \return True if equality is proved; false does not establish inequality.
    *
    * \note Analyzer will call into sub-analyzers to get the result.
    */
   bool CanProveEqual(const PrimExpr& lhs, const PrimExpr& rhs);
   /*!
-   * \brief Whether we can prove lhs is smaller than possibly symbolic shape.
+   * \brief Attempt to prove lhs <= a possibly symbolic shape.
    *
    * By calling this function, the caller gives an extra hint that shape > 0,
    * because it appeared in buffer shape.
@@ -578,16 +677,16 @@ class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
    *
    * \param lhs The input lhs.
    * \param shape The symbolic shape.
-   * \return Whether we can prove lhs <= shape.
+   * \return True if proved using the caller's positive-shape guarantee; false 
otherwise.
    */
   bool CanProveLessEqualThanSymbolicShapeValue(const PrimExpr& lhs, const 
PrimExpr& shape);
   /*!
-   * \brief Whether can we prove condition.
+   * \brief Attempt to prove a condition under the current premises.
    *
    * \param cond The expression to be proved.
-   * \param strength the strength of the prove.
+   * \param strength Proof effort; stronger modes may use symbolic bounds and 
optional Z3.
    *
-   * \return The result.
+   * \return True if proved; false includes unsupported or inconclusive 
queries.
    *
    * \note Analyzer will call into sub-analyzers to get the result.
    * Do not use strength beyond default in sub-analyzers and
@@ -599,28 +698,26 @@ class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
    * \brief Simplify expr.
    *
    * \param expr The expression to be simplified.
-   * \param steps The simplification runs in the order of
-   *        rewrite_simplify (step 1) -> canonical_simplify (step 2) ->
-   *        rewrite_simplify (step 3) -> canonical_simplify (step 4) -> ...
-   *        param steps controls how many steps to run.
-   *        Default is 2, i.e., rewrite_simplify + canonical_simplify.
-   * \return The result.
+   * \param steps Number of alternating rewrite/canonical passes after an 
initial
+   * canonical pass. The default of two runs canonical, rewrite, then 
canonical.
+   * Nonpositive values run only the initial canonical pass. Processing may 
stop
+   * early at a constant expression.
+   * \return An equivalent expression under the current premises.
    *
    * \note Analyzer will call into sub-analyzers to get the result.
    */
   PrimExpr Simplify(const PrimExpr& expr, int steps = 2);
 
   /*!
-   * \brief Deep-copy this analyzer into a new, independent Analyzer.
+   * \brief Copy accepted facts and query settings into an independent 
analyzer.
    *
-   * The returned analyzer carries the same accumulated facts (variable
-   * bounds, modular sets, rewrite/canonical bindings, integer-set domains,
-   * literal constraints and known comparisons) as this one, but owns
-   * its own state: binding or simplifying on either analyzer afterwards does
-   * not affect the other. This is the deep copy that handle-copying an
-   * Analyzer does not provide.
+   * Backend state is independent: subsequent synchronization, simplification,
+   * and query settings on either analyzer do not affect the other. Premise and
+   * expression nodes are shared and must not be mutated through aliases.
+   * Query scratch, solver instances, and accumulated statistics are not 
copied.
+   * Copying an Analyzer handle alone instead shares the same mutable state.
    *
-   * \return A new Analyzer holding an independent copy of the facts.
+   * \return A new analyzer with independent backend state and the same 
accepted premises.
    */
   Analyzer Clone() const;
 
@@ -638,13 +735,21 @@ class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
 
  private:
   friend class detail::TempConstraintScope;
+  // Record a value binding after AnalyzerObj validates and orders the 
premises.
   void IngestBinding(const Var& var, const PrimExpr& expr);
+  // Record a half-open variable range from the accepted premise prefix.
   void IngestBinding(const Var& var, const Range& range);
+  // Dispatch a supported pure premise to the participating backends.
   void IngestConstraint(const Constraint& constraint);
+  // Normalize and derive predicate facts using only the already valid prefix.
   std::vector<PrimExpr> PreparePredicate(const PrimExpr& condition);
+  // Fixed position of the last successfully accepted premise environment.
   ConstraintContext last_snapshot_;
+  // Query-local premises, managed in LIFO order by TempConstraintScope.
   std::vector<Constraint> temp_constraints_;
+  // Prevent reentry and reuse after an incomplete synchronization.
   bool synchronizing_{false};
+  // Nested query count; synchronization requires zero active queries.
   int active_queries_{0};
 };
 
@@ -663,8 +768,9 @@ class TVM_TIRX_DLL AnalyzerObj : public ffi::Object {
  */
 class Analyzer : public ffi::ObjectRef {
  public:
-  /*! \brief Default-construct a fresh analyzer (allocates an AnalyzerObj). */
+  /*! \brief Construct a fresh analyzer. */
   Analyzer() : Analyzer(ffi::make_object<AnalyzerObj>()) {}
+  /*! \brief Adopt a reference to a non-null analyzer object. */
   explicit Analyzer(ffi::ObjectPtr<AnalyzerObj> n) : 
ffi::ObjectRef(std::move(n)) {
     TVM_FFI_ICHECK(this->get() != nullptr);
   }
@@ -682,13 +788,19 @@ class Analyzer : public ffi::ObjectRef {
  */
 class AllowUIntAsIndex {
  public:
-  /*! \brief Whether unsigned index analysis is enabled in the current thread. 
*/
+  /*!
+   * \brief Check the current thread's unsigned-index assumption.
+   * \return True inside an active With<AllowUIntAsIndex> scope.
+   */
   TVM_TIRX_DLL static bool Enabled();
 
  private:
   friend class With<AllowUIntAsIndex>;
+  // Called across the DLL boundary by the inline With<> constructor.
   TVM_TIRX_DLL void EnterWithScope();
+  // Called across the DLL boundary by the inline With<> destructor.
   TVM_TIRX_DLL void ExitWithScope();
+  // Number of active scopes in this thread.
   static thread_local int depth_;
 };
 
diff --git a/include/tvm/sym/constraint.h b/include/tvm/sym/constraint.h
index 9cf94dfc2..98257ab24 100644
--- a/include/tvm/sym/constraint.h
+++ b/include/tvm/sym/constraint.h
@@ -185,10 +185,19 @@ class ConstraintContext;
  *
  * Holds variable bindings, value ranges, and predicates collected during 
traversal.
  * Callbacks can inspect these constraints when processing the current 
expression or statement.
+ * Captured constraint and expression nodes must not be changed through 
aliases: appending
+ * preserves earlier prefixes, but snapshots do not deep-copy their contents.
  */
 class ConstraintContextObj : public ffi::Object {
  public:
+  /*! \brief Construct an empty root context. */
   ConstraintContextObj() = default;
+  /*!
+   * \brief Capture an inherited prefix and start an empty local sequence.
+   * \param parent Non-null parent context.
+   * \param parent_local_prefix Number of parent-local entries to capture.
+   * \throws ffi::Error If parent is null or the prefix is outside [0, 
parent->LocalSize()].
+   */
   ConstraintContextObj(ffi::ObjectPtr<ConstraintContextObj> parent, int64_t 
parent_local_prefix)
       : parent_(std::move(parent)), parent_prefix_size_(parent_local_prefix) {
     TVM_FFI_CHECK(
@@ -196,16 +205,20 @@ class ConstraintContextObj : public ffi::Object {
         ValueError)
         << "Constraint context parent local prefix is out of bounds";
   }
+  // Context nodes have stable identity; use Snapshot to capture their current 
position.
   ConstraintContextObj(const ConstraintContextObj&) = delete;
   ConstraintContextObj& operator=(const ConstraintContextObj&) = delete;
 
   /*!
    * \brief Append a premise locally, preserving every previously captured 
prefix.
+   * \param constraint Premise to retain as supplied, without validation or 
inference.
+   * Its node and referenced expressions must not later be mutated through 
aliases.
    */
   void Append(const Constraint& constraint) { 
constraints_.push_back(constraint); }
 
   /*!
-   * \brief Number of local entries; excludes captured ancestors.
+   * \brief Count the local entries.
+   * \return Local sequence length, excluding captured ancestors.
    */
   int64_t LocalSize() const { return constraints_.size(); }
 
@@ -221,12 +234,16 @@ class ConstraintContextObj : public ffi::Object {
    * context->Append(sym::PredicateConstraint(x < 16));
    * // saved contains x >= 0; context contains both predicates.
    * \endcode
+   * \return An independently extensible context capturing the current prefix.
    */
   ConstraintContext Snapshot() const;
 
   /*!
    * \brief Read constraints in inherited/local order.
-   * The callback receives a const Constraint&. Later appends do not enter 
this iteration.
+   * Later appends do not enter this iteration. The reference passed to the 
callback
+   * is valid only during that invocation; copy the handle to retain the 
premise.
+   * \tparam F Callable accepting a const Constraint&.
+   * \param f Callback invoked once per captured premise, in inherited/local 
order.
    */
   template <typename F>
   void ForEach(F&& f) const {
@@ -239,16 +256,20 @@ class ConstraintContextObj : public ffi::Object {
    * \brief Returns an independent array of the constraints in this context.
    * Includes inherited constraints in order. Later additions to the context 
do not
    * change the returned array. Edits to the array do not change this context.
-   * Constraint objects remain shared.
+   * Constraint objects remain shared and must not be mutated through aliases.
+   * \return A copy-on-write array containing the captured premises.
    */
   ffi::Array<Constraint> ToArray() const { return ToArray(LocalSize()); }
 
+  /*! \brief Allow appending through a const context handle. */
   static constexpr bool _type_mutable = true;
+  /*! \brief Register the context methods exposed through FFI reflection. */
   static void RegisterReflection();
   TVM_FFI_DECLARE_OBJECT_INFO_FINAL("sym.ConstraintContext", 
ConstraintContextObj, ffi::Object);
 
  private:
   friend class AnalyzerObj;
+  // Materialize the fixed inherited sequence and the requested local prefix.
   ffi::Array<Constraint> ToArray(int64_t local_prefix) const {
     if (!parent_) {
       if (local_prefix == LocalSize()) return constraints_;
@@ -261,6 +282,7 @@ class ConstraintContextObj : public ffi::Object {
     return result;
   }
 
+  // Traverse a fixed prefix even if callbacks append more local constraints.
   template <typename F>
   void ForEach(int64_t local_prefix, F&& f) const {
     if (parent_) parent_->ForEach(parent_prefix_size_, f);
@@ -275,13 +297,7 @@ class ConstraintContextObj : public ffi::Object {
   const ffi::ObjectPtr<ConstraintContextObj> parent_;
   // Fixed prefix length in the parent's LOCAL sequence, not its effective 
count.
   const int64_t parent_prefix_size_{0};
-  /*!
-   * \brief Append-only sequence of constraints local to this context.
-   *
-   * New entries may be appended at the end. Existing entries must not be
-   * removed, replaced, reordered, or modified through aliases. Appending
-   * preserves the contents and meaning of every previously captured prefix.
-   */
+  // Append-only local sequence; captured entries cannot be replaced or 
mutated through aliases.
   ffi::Array<Constraint> constraints_;
 };
 
@@ -290,9 +306,7 @@ class ConstraintContextObj : public ffi::Object {
  */
 class ConstraintContext : public ffi::ObjectRef {
  public:
-  /*!
-   * \brief Construct an empty root.
-   */
+  /*! \brief Construct an empty root. */
   ConstraintContext() : 
ffi::ObjectRef(ffi::make_object<ConstraintContextObj>()) {}
   /*!
    * \brief Construct a child capturing [0, parent_local_prefix) of its 
parent's local entries.
@@ -300,13 +314,12 @@ class ConstraintContext : public ffi::ObjectRef {
    * \param parent Context supplying inherited constraints.
    * \param parent_local_prefix Number of parent-local entries to capture, 
between zero
    * and parent->LocalSize(), inclusive.
+   * \throws ffi::Error If the prefix is outside that range.
    */
   ConstraintContext(ConstraintContext parent, int64_t parent_local_prefix)
       : ffi::ObjectRef(ffi::make_object<ConstraintContextObj>(
             ffi::GetObjectPtr<ConstraintContextObj>(parent.get()), 
parent_local_prefix)) {}
-  /*!
-   * \brief Adopt an existing context object.
-   */
+  /*! \brief Adopt a reference to a non-null context object. */
   explicit ConstraintContext(ffi::ObjectPtr<ConstraintContextObj> node)
       : ffi::ObjectRef(std::move(node)) {}
   TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(ConstraintContext, 
ffi::ObjectRef,
diff --git a/src/sym/z3_prover.cc b/src/sym/z3_prover.cc
index 88fc7ef9b..623447171 100644
--- a/src/sym/z3_prover.cc
+++ b/src/sym/z3_prover.cc
@@ -984,10 +984,10 @@ TVM_TIRX_DLL bool Z3Prover::CanProve(const PrimExpr& 
expr) {
   detail::TempConstraintScope query(impl_->analyzer);
   return impl_->CanProve(expr, 
detail::TempConstraintScope::Query(impl_->analyzer));
 }
-TVM_TIRX_DLL void Z3Prover::IngestBinding(const Var& var, const Range& 
new_range) {
+void Z3Prover::IngestBinding(const Var& var, const Range& new_range) {
   return impl_->IngestBinding(var, new_range, true);
 }
-TVM_TIRX_DLL void Z3Prover::IngestBinding(const Var& var, const PrimExpr& 
expr) {
+void Z3Prover::IngestBinding(const Var& var, const PrimExpr& expr) {
   return impl_->IngestBinding(var, expr, true);
 }
 void Z3Prover::IngestPredicate(const PrimExpr& constraint) {
@@ -1050,8 +1050,8 @@ TVM_TIRX_DLL bool Z3Prover::CanProve(const PrimExpr& 
expr) {
   detail::TempConstraintScope query(impl_->analyzer);
   return false;
 }
-TVM_TIRX_DLL void Z3Prover::IngestBinding(const Var& var, const Range& 
new_range) {}
-TVM_TIRX_DLL void Z3Prover::IngestBinding(const Var& var, const PrimExpr& 
expr) {}
+void Z3Prover::IngestBinding(const Var& var, const Range& new_range) {}
+void Z3Prover::IngestBinding(const Var& var, const PrimExpr& expr) {}
 void Z3Prover::IngestPredicate(const PrimExpr& constraint) {}
 ffi::String Z3Prover::GetSMTLIB2(const ffi::Optional<PrimExpr> expr) {
   detail::TempConstraintScope query(impl_->analyzer);

Reply via email to