Program Listing for File stmt_functor.h

Program Listing for File stmt_functor.h#

↰ Return to documentation for file (tvm/tirx/stmt_functor.h)

/*
 * 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.
 */

#ifndef TVM_TIRX_STMT_FUNCTOR_H_
#define TVM_TIRX_STMT_FUNCTOR_H_

#include <tvm/ir/expr_functor.h>
#include <tvm/ir/object_functor.h>
#include <tvm/ir/prim/expr.h>
#include <tvm/tirx/function.h>
#include <tvm/tirx/stmt.h>

#include <unordered_map>
#include <utility>

namespace tvm {
namespace tirx {
template <typename FType>
class StmtFunctor;

template <typename R, typename... Args>
class StmtFunctor<R(const Stmt&, Args...)> {
 private:
  using TSelf = StmtFunctor<R(const Stmt&, Args...)>;

 public:
  using result_type = R;
  StmtFunctor() : StmtFunctor(GlobalVTable()) {}
  virtual ~StmtFunctor() = default;
  TVM_FFI_INLINE R operator()(const Stmt& node, Args... args) {
    return Dispatch(node, std::forward<Args>(args)...);
  }
  TVM_FFI_INLINE virtual R Dispatch(const Stmt& node, Args... args) {
    TVM_FFI_ICHECK(node.defined()) << "Cannot dispatch a null statement";
    try {
      return (*vtable_)(node, this, std::forward<Args>(args)...);
    } catch (ffi::Error& error) {
      ffi::detail::UpdateVisitErrorContext(error, node);
      throw;
    }
  }

  virtual R Dispatch_(const BindObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const RegionStmtObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const IfObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const ForObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const WhileObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const ReturnObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const BreakObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const ContinueObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const TensorStoreObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const AssertStmtObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const SeqStmtObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R Dispatch_(const EvaluateObj* node, Args... args) {
    return DispatchDefault_(node, std::forward<Args>(args)...);
  }
  virtual R DispatchDefault_(const ffi::Object* node, Args...) {
    TVM_FFI_THROW(InternalError) << "Do not have a default for " << node->GetTypeKey();
    TVM_FFI_UNREACHABLE();
  }

 protected:
  using VTable = ObjectFunctor<R(const ffi::ObjectRef&, TSelf*, Args...)>;
  explicit StmtFunctor(const VTable* vtable) : vtable_(vtable) {}
  static void InitVTable(VTable* vtable) {
    vtable->template SetDispatch<StmtObj>(
        [](const ffi::ObjectRef& node, TSelf* self, Args... args) -> R {
          return self->DispatchDefault_(node.get(), std::forward<Args>(args)...);
        });
    SetDispatch<TSelf, BindObj>(vtable);
    SetDispatch<TSelf, RegionStmtObj>(vtable);
    SetDispatch<TSelf, IfObj>(vtable);
    SetDispatch<TSelf, ForObj>(vtable);
    SetDispatch<TSelf, WhileObj>(vtable);
    SetDispatch<TSelf, ReturnObj>(vtable);
    SetDispatch<TSelf, BreakObj>(vtable);
    SetDispatch<TSelf, ContinueObj>(vtable);
    SetDispatch<TSelf, TensorStoreObj>(vtable);
    SetDispatch<TSelf, AssertStmtObj>(vtable);
    SetDispatch<TSelf, SeqStmtObj>(vtable);
    SetDispatch<TSelf, EvaluateObj>(vtable);
  }
  template <typename Self, typename Node>
  static void SetDispatch(VTable* vtable) {
    vtable->template SetDispatch<Node>(
        [](const ffi::ObjectRef& node, TSelf* self, Args... args) -> R {
          return static_cast<Self*>(self)->Dispatch_(static_cast<const Node*>(node.get()),
                                                     std::forward<Args>(args)...);
        });
  }

 private:
  static const VTable* GlobalVTable() {
    static const VTable table = [] {
      VTable table;
      InitVTable(&table);
      table.Finalize();
      return table;
    }();
    return &table;
  }
  const VTable* vtable_;
};

class TVM_TIRX_DLL StmtExprVisitor : public tvm::ExprVisitor {
 public:
  TVM_DEFINE_OBJECT_FUNCTOR_DEFAULT_CONSTRUCTOR(StmtExprVisitor, tvm::ExprVisitor)

  using tvm::ExprVisitor::Visit;
  using tvm::ExprVisitor::Visit_;

  virtual ffi::Optional<VisitInterrupt> Visit_(const BindObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const RegionStmtObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const IfObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const ForObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const WhileObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const ReturnObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const BreakObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const ContinueObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const TensorStoreObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const AssertStmtObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const SeqStmtObj* op);
  virtual ffi::Optional<VisitInterrupt> Visit_(const EvaluateObj* op);

  // Preserve TIRx operand traversal where it differs from the shared defaults.
  ffi::Optional<VisitInterrupt> Visit_(const VarObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const TensorLoadObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const OpaqueExprObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const TupleObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const TupleGetItemObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const CallObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const prim::LetObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const prim::RampObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const prim::BroadcastObj* op) override;
  ffi::Optional<VisitInterrupt> Visit_(const prim::ShuffleObj* op) override;

 protected:
  explicit StmtExprVisitor(const VTable* vtable) : tvm::ExprVisitor(vtable) {}
  static void InitVTable(VTable* vtable);
};

class TVM_TIRX_DLL StmtExprMutator : public tvm::ExprMutator {
 public:
  TVM_DEFINE_OBJECT_FUNCTOR_DEFAULT_CONSTRUCTOR(StmtExprMutator, tvm::ExprMutator)
  using tvm::ExprMutator::Mutate;
  using tvm::ExprMutator::Mutate_;

  TVM_FFI_INLINE UnchangedOr<Stmt> Mutate(const Stmt& stmt,
                                          InplaceMode inplace_mode = InplaceMode::kDisallow) {
    return ffi::detail::UnchangedOrUnsafe::MoveFromTVMFFIAny<Stmt>(
        ffi::detail::UnchangedOrUnsafe::MoveToTVMFFIAny(Mutate(ffi::AnyView(stmt), inplace_mode)));
  }

  TVM_FFI_INLINE UnchangedOr<SeqStmt> Mutate(const SeqStmt& stmt,
                                             InplaceMode inplace_mode = InplaceMode::kDisallow) {
    auto result = Mutate(static_cast<const Stmt&>(stmt), inplace_mode);
    if (result.UnchangedOrSameAs(stmt)) return ffi::Unchanged();
    return SeqStmt(std::move(result).ValueUnchecked());
  }

  TVM_FFI_INLINE UnchangedOr<ffi::Optional<SeqStmt>> Mutate(
      const ffi::Optional<SeqStmt>& stmt, InplaceMode inplace_mode = InplaceMode::kDisallow) {
    if (!stmt.has_value()) return ffi::Unchanged();
    auto result = Mutate(stmt.value(), inplace_mode);
    if (result.IsUnchanged()) return ffi::Unchanged();
    return ffi::Optional<SeqStmt>(std::move(result).ValueUnchecked());
  }

  TVM_FFI_INLINE UnchangedOr<ffi::Optional<Stmt>> Mutate(
      const ffi::Optional<Stmt>& stmt, InplaceMode inplace_mode = InplaceMode::kDisallow) {
    if (!stmt.has_value()) return ffi::Unchanged();
    auto result = Mutate(stmt.value(), inplace_mode);
    if (result.IsUnchanged()) return ffi::Unchanged();
    return ffi::Optional<Stmt>(std::move(result).ValueUnchecked());
  }

  virtual UnchangedOr<Stmt> Mutate_(const BindObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const RegionStmtObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const IfObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const ForObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const WhileObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const ReturnObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const BreakObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const ContinueObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const TensorStoreObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const AssertStmtObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const SeqStmtObj* op, InplaceMode inplace_mode);
  virtual UnchangedOr<Stmt> Mutate_(const EvaluateObj* op, InplaceMode inplace_mode);

 protected:
  explicit StmtExprMutator(const VTable* vtable) : tvm::ExprMutator(vtable) {}
  static void InitVTable(VTable* vtable);
};

TVM_TIRX_DLL Stmt SubstituteWithDataTypeLegalization(
    Stmt stmt, ffi::TypedFunction<ffi::Optional<PrimExpr>(const Var&)> vmap);

TVM_TIRX_DLL PrimExpr SubstituteWithDataTypeLegalization(
    PrimExpr expr, ffi::TypedFunction<ffi::Optional<PrimExpr>(const Var&)> vmap);

template <typename Node, typename = std::enable_if_t<std::is_base_of_v<StmtObj, Node>>>
bool ContainsNode(const Stmt& stmt) {
  struct Visitor : StmtExprVisitor {
    // Early bail-out, if we already found the node. Skip expression operands.
    ffi::Optional<VisitInterrupt> Visit(ffi::AnyView value) final {
      if (contains_node || value.as<ExprObj>()) {
        return std::nullopt;
      }
      if (value.as<Node>()) {
        contains_node = true;
        return std::nullopt;
      }
      return StmtExprVisitor::Visit(value);
    }

    bool contains_node{false};
  };

  auto visitor = ffi::make_object<Visitor>();
  visitor->Visit(stmt);
  return visitor->contains_node;
}

}  // namespace tirx
}  // namespace tvm

#endif  // TVM_TIRX_STMT_FUNCTOR_H_