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.git
The following commit(s) were added to refs/heads/main by this push:
new 319b760d27 [REFACTOR][Arith] Inline bound-check Ramp expression
(#20349)
319b760d27 is described below
commit 319b760d27c61cf69b682f6d5975c98b1085094a
Author: Tianqi Chen <[email protected]>
AuthorDate: Tue Sep 15 17:37:54 2026 -0400
[REFACTOR][Arith] Inline bound-check Ramp expression (#20349)
Inline the bound checker's sole guarded Ramp scalarizer call as `base +
lanes * stride`, preserving the existing operands and multiplication
order. Remove the unused private scalarizer header, implementation and
include.
The change affects three source paths and retains existing bound-check
behavior. No helper references remain.
Validation: compiler build and clang-format passed; 74 existing tests
passed (rank-zero bound checker: 1, vectorization: 73). These suites do
not directly cover the guarded Ramp instrumentation path; source audit
confirms the old and new expressions are identical.
---
src/arith/unwrap_vector_expr.cc | 195 -----------------------------------
src/arith/unwrap_vector_expr.h | 56 ----------
src/s_tir/transform/bound_checker.cc | 4 +-
3 files changed, 1 insertion(+), 254 deletions(-)
diff --git a/src/arith/unwrap_vector_expr.cc b/src/arith/unwrap_vector_expr.cc
deleted file mode 100644
index 7c583fefb0..0000000000
--- a/src/arith/unwrap_vector_expr.cc
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file unwrap_vector_expr.cc
- * \brief Utility for tracking currently active constraints
- */
-
-#include "unwrap_vector_expr.h"
-
-#include <tvm/arith/analyzer.h>
-#include <tvm/ffi/cast.h>
-#include <tvm/ir/expr_functor.h>
-#include <tvm/ir/prim/builtin.h>
-#include <tvm/ir/prim/expr.h>
-#include <tvm/tirx/analysis.h>
-#include <tvm/tirx/buffer.h>
-#include <tvm/tirx/builtin.h>
-#include <tvm/tirx/op.h>
-
-#include <unordered_map>
-#include <utility>
-
-namespace tvm {
-namespace arith {
-
-using namespace tirx;
-
-class Scalarizer : public tvm::ExprMutator {
- public:
- explicit Scalarizer(PrimExpr lane) : lane_(lane) {}
-
-#define TVM_SCALARIZER_BINARY_MUTATE_(Name)
\
- UnchangedOr<PrimExpr> Mutate_(const prim::Name##Node* op, InplaceMode
inplace_mode) final { \
- return Rebuild(op, [](const prim::Name##Node* node) { return
prim::Name(node->a, node->b); }); \
- }
-
- TVM_SCALARIZER_BINARY_MUTATE_(Add);
- TVM_SCALARIZER_BINARY_MUTATE_(Sub);
- TVM_SCALARIZER_BINARY_MUTATE_(Mul);
- TVM_SCALARIZER_BINARY_MUTATE_(Div);
- TVM_SCALARIZER_BINARY_MUTATE_(Mod);
- TVM_SCALARIZER_BINARY_MUTATE_(FloorDiv);
- TVM_SCALARIZER_BINARY_MUTATE_(FloorMod);
- TVM_SCALARIZER_BINARY_MUTATE_(Min);
- TVM_SCALARIZER_BINARY_MUTATE_(Max);
- TVM_SCALARIZER_BINARY_MUTATE_(EQ);
- TVM_SCALARIZER_BINARY_MUTATE_(NE);
- TVM_SCALARIZER_BINARY_MUTATE_(LT);
- TVM_SCALARIZER_BINARY_MUTATE_(LE);
- TVM_SCALARIZER_BINARY_MUTATE_(GT);
- TVM_SCALARIZER_BINARY_MUTATE_(GE);
- TVM_SCALARIZER_BINARY_MUTATE_(And);
- TVM_SCALARIZER_BINARY_MUTATE_(Or);
-
-#undef TVM_SCALARIZER_BINARY_MUTATE_
-
- UnchangedOr<PrimExpr> Mutate_(const prim::CastNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const prim::CastNode* node) {
- return prim::Cast(node->ExprNode::ty.as_or_throw<PrimType>(),
node->value);
- });
- }
-
- UnchangedOr<PrimExpr> Mutate_(const prim::NotNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const prim::NotNode* node) { return
prim::Not(node->a); });
- }
-
- UnchangedOr<PrimExpr> Mutate_(const prim::SelectNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const prim::SelectNode* node) {
- return prim::Select(node->condition, node->true_value,
node->false_value);
- });
- }
-
- UnchangedOr<PrimExpr> Mutate_(const prim::ShuffleNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const prim::ShuffleNode* node) {
- return prim::Shuffle(node->vectors, node->indices);
- });
- }
-
- UnchangedOr<Expr> Mutate_(const TupleNode* op, InplaceMode inplace_mode)
final {
- return Rebuild(op, [](const TupleNode* node) { return
tvm::Tuple(node->fields, node->span); });
- }
-
- UnchangedOr<Expr> Mutate_(const TupleGetItemNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const TupleGetItemNode* node) {
- return TupleGetItem(node->tuple, node->index, node->span);
- });
- }
-
- UnchangedOr<PrimExpr> Mutate_(const TensorLoadNode* op, InplaceMode
inplace_mode) final {
- return Rebuild(op, [](const TensorLoadNode* node) {
- return tirx::BufferLoad(node->source.as_or_throw<tirx::BufferVar>(),
node->indices,
- node->span);
- });
- }
-
- UnchangedOr<Expr> Mutate_(const CallNode* op, InplaceMode inplace_mode)
final {
- return Rebuild(op, [op](const CallNode* node) -> Expr {
- if (!op->op.same_as(tirx::builtin::buffer_data()) ||
node->args.same_as(op->args)) {
- return ffi::GetRef<Call>(node);
- }
- TVM_FFI_ICHECK_EQ(node->args.size(), 1);
- const auto* buffer_var = node->args[0].as<VarNode>();
- TVM_FFI_ICHECK(buffer_var);
- const auto* buffer_type = buffer_var->ty.as<tirx::BufferTypeNode>();
- TVM_FFI_ICHECK(buffer_type);
- return Call(buffer_type->DataPointerType(), node->op, node->args,
node->attrs, node->ty_args,
- node->span);
- });
- }
-
- UnchangedOr<PrimExpr> Mutate_(const prim::RampNode* op, InplaceMode
inplace_mode) final {
- return op->base + lane_ * op->stride;
- }
-
- UnchangedOr<PrimExpr> Mutate_(const prim::BroadcastNode* op, InplaceMode
inplace_mode) final {
- return op->value;
- }
-
- UnchangedOr<Expr> Mutate_(const VarNode* op, InplaceMode inplace_mode) final
{
- auto it = let_var_remap_.find(op);
- if (it != let_var_remap_.end()) {
- return it->second;
- } else {
- return tvm::ExprMutator::Mutate_(op, inplace_mode);
- }
- }
- UnchangedOr<PrimExpr> Mutate_(const prim::LetNode* op, InplaceMode
inplace_mode) final {
- PrimType value_ty = op->value.ty();
- if (value_ty.lanes() == 1) {
- return Rebuild(op, [](const prim::LetNode* node) {
- return prim::Let(node->var, node->value, node->body);
- });
- }
-
- auto it = let_var_remap_.find(op->var.get());
- TVM_FFI_ICHECK(it == let_var_remap_.end()) << "Duplicate binding of
variable " << op->var;
-
- PrimType var_ty = op->var.as_or_throw<PrimVar>().ty();
- PrimVar new_var(op->var->name + "_scalar", var_ty.WithLanes(1));
- let_var_remap_[op->var.get()] = new_var;
- struct RemapGuard {
- std::unordered_map<const VarNode*, PrimVar>& remap;
- const VarNode* var;
- ~RemapGuard() { remap.erase(var); }
- } remap_guard{let_var_remap_, op->var.get()};
-
- PrimExpr value = Mutate(op->value,
inplace_mode).ValueOrUnchanged(op->value);
- PrimExpr body = Mutate(op->body, inplace_mode).ValueOrUnchanged(op->body);
-
- return prim::Let(op->var, value, body);
- }
-
- private:
- // Scalarized children can change a node's result type. Reuse native child
mutation,
- // then the existing constructors to derive the type and check their
invariants.
- // Disable in-place mutation so changed children cannot be reported as
Unchanged.
- template <typename Node, typename F>
- auto Rebuild(const Node* op, F rebuild)
- -> decltype(tvm::ExprMutator::Mutate_(op, InplaceMode::kDisallow)) {
- auto rewritten_u = tvm::ExprMutator::Mutate_(op, InplaceMode::kDisallow);
- if (rewritten_u.IsUnchanged()) return ffi::Unchanged();
- auto rewritten = std::move(rewritten_u).ValueUnchecked();
- return rebuild(static_cast<const Node*>(rewritten.get()));
- }
-
- // The lane to extract
- PrimExpr lane_;
-
- // Let binding
- std::unordered_map<const VarNode*, PrimVar> let_var_remap_;
-};
-
-PrimExpr UnwrapVectorExpr(const PrimExpr& vector_expr, const PrimExpr& lane) {
- return
ffi::make_object<Scalarizer>(lane)->Mutate(vector_expr).ValueOrUnchanged(vector_expr);
-}
-
-} // namespace arith
-} // namespace tvm
diff --git a/src/arith/unwrap_vector_expr.h b/src/arith/unwrap_vector_expr.h
deleted file mode 100644
index a63bce289f..0000000000
--- a/src/arith/unwrap_vector_expr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-/*!
- * \file unwrap_vector_expr.h
- *
- * \brief Centralized location for extraction of constraints from a boolean
expression.
- */
-
-#ifndef TVM_ARITH_UNWRAP_VECTOR_EXPR_H_
-#define TVM_ARITH_UNWRAP_VECTOR_EXPR_H_
-
-#include <tvm/ir/prim/expr.h>
-
-#include <vector>
-
-namespace tvm {
-namespace arith {
-
-/* \brief Unwraps a component of a vector expression
- *
- * Utility to break up a vector expression into a specific component
- * of the expression.
- *
- * Example: `Ramp(start, stride, n)` => `start + stride*lane`
- * Example: `Broadcast(value, n)` => `value`
- * Example: `2*Ramp(start, stride, n) + Broadcast(value,n)` => `2*(start +
stride*lane) + value`
- *
- * \param vector_expr The vectorized expression to examine
- *
- * \param lane Which lane of the vectorized expression to extract.
- *
- * \returns A scalar expression
- */
-PrimExpr UnwrapVectorExpr(const PrimExpr& vector_expr, const PrimExpr& lane);
-
-} // namespace arith
-} // namespace tvm
-
-#endif // TVM_ARITH_UNWRAP_VECTOR_EXPR_H_
diff --git a/src/s_tir/transform/bound_checker.cc
b/src/s_tir/transform/bound_checker.cc
index 2cdda15dd9..636fb670e6 100644
--- a/src/s_tir/transform/bound_checker.cc
+++ b/src/s_tir/transform/bound_checker.cc
@@ -38,8 +38,6 @@
#include <utility>
#include <vector>
-#include "../../arith/unwrap_vector_expr.h"
-
namespace tvm {
namespace s_tir {
using namespace tvm::prim;
@@ -209,7 +207,7 @@ class BoundChecker : public StmtExprMutator {
PrimExpr upper_bound = shape[i];
if (const RampNode* ramp_index = index.as<RampNode>()) {
- index = arith::UnwrapVectorExpr(ffi::GetRef<Ramp>(ramp_index),
ramp_index->lanes);
+ index = ramp_index->base + ramp_index->lanes * ramp_index->stride;
}
// Try to simplify index and bound.