Program Listing for File stmt.h

Program Listing for File stmt.h#

↰ Return to documentation for file (tvm/ir/stmt.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_IR_STMT_H_
#define TVM_IR_STMT_H_

#include <tvm/ffi/reflection/registry.h>
#include <tvm/ir/op.h>
#include <tvm/ir/prim/expr.h>

#include <initializer_list>
#include <optional>
#include <string>
#include <utility>

namespace tvm {

class StmtObj : public ffi::Object {
 public:
  mutable Location loc = UnknownLoc();

  StmtObj() = default;
  explicit StmtObj(Location loc) : loc(loc) {}

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<StmtObj>().def_ro("loc", &StmtObj::loc, refl::AttachFieldFlag::SEqHashIgnore());
  }

  static constexpr TVMFFISEqHashKind _type_s_eq_hash_kind = kTVMFFISEqHashKindTreeNode;
  static constexpr bool _type_s_eq_hash_subclass_kind_fixed = true;

  static constexpr const uint32_t _type_child_slots = 15;
  TVM_FFI_DECLARE_OBJECT_INFO("ir.Stmt", StmtObj, ffi::Object);
};

class Stmt : public ffi::ObjectRef {
 public:
  explicit Stmt(ffi::ObjectPtr<StmtObj> node) : ffi::ObjectRef(std::move(node)) {
    TVM_FFI_CHECK(defined(), ValueError) << "Stmt expects a defined node";
  }

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Stmt, ffi::ObjectRef, StmtObj);
};

class SeqStmtObj : public StmtObj {
 public:
  ffi::Array<Stmt> seq;

  size_t size() const { return seq.size(); }
  Stmt operator[](size_t index) const { return seq[index]; }

  TVM_TIRX_DLL static void RegisterReflection();
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.SeqStmt", SeqStmtObj, StmtObj);
};

class SeqStmt : public Stmt {
 public:
  TVM_TIRX_DLL explicit SeqStmt(ffi::Array<Stmt> seq, Location loc = UnknownLoc());
  TVM_TIRX_DLL SeqStmt(Stmt stmt, ffi::Optional<Location> loc = std::nullopt);
  SeqStmt(std::initializer_list<Stmt> seq, Location loc = UnknownLoc())
      : SeqStmt(ffi::Array<Stmt>(seq), std::move(loc)) {}

  size_t size() const { return operator->()->size(); }
  Stmt operator[](size_t index) const { return (*(operator->()))[index]; }
  explicit SeqStmt(ffi::ObjectPtr<SeqStmtObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(SeqStmt, Stmt, SeqStmtObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(SeqStmtObj);
};

namespace ffi {
template <>
inline constexpr bool use_default_type_traits_v<SeqStmt> = false;

template <>
struct TypeTraits<SeqStmt> : public ObjectRefWithFallbackTraitsBase<SeqStmt, Stmt, Array<Stmt>> {
  static SeqStmt ConvertFallbackValue(Stmt stmt) { return SeqStmt(std::move(stmt)); }
  static SeqStmt ConvertFallbackValue(Array<Stmt> seq) { return SeqStmt(std::move(seq)); }
};
}  // namespace ffi

class BindObj : public StmtObj {
 public:
  explicit BindObj(ffi::UnsafeInit tag) : var(tag), value(tag) {}

  BindObj(Var var, Expr value) : var(std::move(var)), value(std::move(value)) {}

  Var var;
  Expr value;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<BindObj>()
        .def_ro("var", &BindObj::var, refl::AttachFieldFlag::SEqHashDefSimple())
        .def_ro("value", &BindObj::value);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Bind", BindObj, StmtObj);
};

class Bind : public Stmt {
 public:
  TVM_TIRX_DLL Bind(Var var, Expr value, Location loc = UnknownLoc());

  explicit Bind(ffi::ObjectPtr<BindObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Bind, Stmt, BindObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(BindObj);
};

TVM_TIRX_DLL bool IsRegionOp(const Op& op);

TVM_TIRX_DLL ffi::Array<Var> GetRegionBodyParams(Op op, ffi::Array<Expr> args, DictAttrs attrs);

class RegionStmtObj : public StmtObj {
 public:
  Op op;
  ffi::Array<Expr> args;
  ffi::Array<Var> body_params;
  DictAttrs attrs;
  SeqStmt body;
  ffi::Array<Var> result_vars;

  explicit RegionStmtObj(ffi::UnsafeInit tag) : op(tag), body(tag) {}

  RegionStmtObj(Op op, SeqStmt body) : op(std::move(op)), body(std::move(body)) {}

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<RegionStmtObj>()
        .def_ro("op", &RegionStmtObj::op)
        .def_ro("attrs", &RegionStmtObj::attrs)
        .def_ro("args", &RegionStmtObj::args)
        .def_ro("body_params", &RegionStmtObj::body_params,
                refl::AttachFieldFlag::SEqHashDefSimple())
        .def_ro("body", &RegionStmtObj::body)
        .def_ro("result_vars", &RegionStmtObj::result_vars,
                refl::AttachFieldFlag::SEqHashDefSimple());
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.RegionStmt", RegionStmtObj, StmtObj);
};

class RegionStmt : public Stmt {
 public:
  TVM_TIRX_DLL RegionStmt(Op op, ffi::Array<Expr> args, ffi::Array<Var> body_params,
                          DictAttrs attrs, SeqStmt body, ffi::Array<Var> result_vars = {},
                          Location loc = UnknownLoc());

  explicit RegionStmt(ffi::ObjectPtr<RegionStmtObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(RegionStmt, Stmt, RegionStmtObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(RegionStmtObj);
};

namespace op_attr {
inline constexpr ffi::reflection::AttrKey<
    ffi::reflection::NativeFunctionView<ffi::Array<Var>(const CallObj* call)>>
    kRegionGetBodyParams{"FRegionGetBodyParams"};
inline constexpr ffi::reflection::AttrKey<
    ffi::reflection::NativeFunctionView<void(const RegionStmtObj*)>>
    kRegionValidate{"FRegionValidate"};
}  // namespace op_attr

// Compatibility names; new callers can deduce the value type from the key.
using FRegionGetBodyParams = decltype(op_attr::kRegionGetBodyParams)::ValueType;
using FRegionValidate = decltype(op_attr::kRegionValidate)::ValueType;

class AssertStmtObj : public StmtObj {
 public:
  explicit AssertStmtObj(ffi::UnsafeInit tag) : condition(tag), error_kind(tag) {}

  AssertStmtObj(PrimExpr condition, StringImm error_kind)
      : condition(std::move(condition)), error_kind(std::move(error_kind)) {}

  PrimExpr condition;
  StringImm error_kind;
  ffi::Array<StringImm> message_parts;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<AssertStmtObj>()
        .def_ro("condition", &AssertStmtObj::condition)
        .def_ro("error_kind", &AssertStmtObj::error_kind)
        .def_ro("message_parts", &AssertStmtObj::message_parts);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.AssertStmt", AssertStmtObj, StmtObj);
};

class AssertStmt : public Stmt {
 public:
  TVM_TIRX_DLL AssertStmt(PrimExpr condition, StringImm error_kind,
                          ffi::Array<StringImm> message_parts, Location loc = UnknownLoc());

  explicit AssertStmt(ffi::ObjectPtr<AssertStmtObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(AssertStmt, Stmt, AssertStmtObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(AssertStmtObj);
};

class TensorStoreObj : public StmtObj {
 public:
  explicit TensorStoreObj(ffi::UnsafeInit tag) : dest(tag), value(tag) {}

  TensorStoreObj(Expr dest, PrimExpr value) : dest(std::move(dest)), value(std::move(value)) {}

  Expr dest;
  ffi::Array<PrimExpr> indices;
  PrimExpr value;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<TensorStoreObj>()
        .def_ro("dest", &TensorStoreObj::dest)
        .def_ro("indices", &TensorStoreObj::indices)
        .def_ro("value", &TensorStoreObj::value);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.TensorStore", TensorStoreObj, StmtObj);
};

class TensorStore : public Stmt {
 public:
  TVM_TIRX_DLL explicit TensorStore(Expr dest, ffi::Array<PrimExpr> indices, PrimExpr value,
                                    Location loc = UnknownLoc());

  explicit TensorStore(ffi::ObjectPtr<TensorStoreObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(TensorStore, Stmt, TensorStoreObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(TensorStoreObj);
};

namespace type_attr {
inline constexpr ffi::reflection::AttrKey<ffi::reflection::NativeFunctionView<void(
    const Expr&, const ffi::Array<PrimExpr>&, const PrimExpr&)>>
    kTensorStoreValidateByTy{"__tvm_tensor_store_validate__"};
}  // namespace type_attr

class EvaluateObj : public StmtObj {
 public:
  explicit EvaluateObj(ffi::UnsafeInit tag) : value(tag) {}

  explicit EvaluateObj(Expr value) : value(std::move(value)) {}

  Expr value;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<EvaluateObj>().def_ro("value", &EvaluateObj::value);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Evaluate", EvaluateObj, StmtObj);
};

class Evaluate : public Stmt {
 public:
  TVM_TIRX_DLL explicit Evaluate(Expr value, Location loc = UnknownLoc());

  explicit Evaluate(int value, Location loc = UnknownLoc()) : Evaluate(PrimExpr(value), loc) {}

  explicit Evaluate(ffi::ObjectPtr<EvaluateObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Evaluate, Stmt, EvaluateObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(EvaluateObj);
};

class IfObj : public StmtObj {
 public:
  explicit IfObj(ffi::UnsafeInit tag) : condition(tag), then_case(tag) {}

  IfObj(PrimExpr condition, SeqStmt then_case)
      : condition(std::move(condition)), then_case(std::move(then_case)) {}

  PrimExpr condition;
  SeqStmt then_case;
  ffi::Optional<SeqStmt> else_case;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<IfObj>()
        .def_ro("condition", &IfObj::condition)
        .def_ro("then_case", &IfObj::then_case)
        .def_ro("else_case", &IfObj::else_case);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.If", IfObj, StmtObj);
};

class If : public Stmt {
 public:
  TVM_TIRX_DLL If(PrimExpr condition, SeqStmt then_case,
                  ffi::Optional<SeqStmt> else_case = std::nullopt, Location loc = UnknownLoc());

  explicit If(ffi::ObjectPtr<IfObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(If, Stmt, IfObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(IfObj);
};

enum class ForKind : int {
  kDefault = 0,
  kParallel = 1,
  kVectorized = 2,
  kUnrolled = 3,
};

class ForObj : public StmtObj {
 public:
  explicit ForObj(ffi::UnsafeInit tag) : var(tag), begin(tag), end(tag), step(tag), body(tag) {}

  ForObj(PrimVar var, PrimExpr begin, PrimExpr end, PrimExpr step, ForKind kind, SeqStmt body)
      : var(std::move(var)),
        begin(std::move(begin)),
        end(std::move(end)),
        step(std::move(step)),
        kind(kind),
        body(std::move(body)) {}

  PrimVar var;
  PrimExpr begin;
  PrimExpr end;
  PrimExpr step;
  ForKind kind;
  SeqStmt body;
  ffi::Map<ffi::String, ffi::Any> annotations;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<ForObj>()
        .def_ro("var", &ForObj::var, refl::AttachFieldFlag::SEqHashDefSimple())
        .def_ro("begin", &ForObj::begin)
        .def_ro("end", &ForObj::end)
        // Reflection stores one typed default. Wider unit steps remain distinct.
        .def_ro("step", &ForObj::step, refl::DefaultValue(IntImm::Int32(1)))
        .def_ro("kind", &ForObj::kind, refl::DefaultValue(ForKind::kDefault))
        .def_ro("body", &ForObj::body)
        .def_ro("annotations", &ForObj::annotations,
                refl::DefaultValue(ffi::Map<ffi::String, ffi::Any>()));
  }

  TVM_TIRX_DLL bool HasTrivialStep() const;

  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.For", ForObj, StmtObj);
};

class For : public Stmt {
 public:
  TVM_TIRX_DLL For(PrimVar var, PrimExpr begin, PrimExpr end, PrimExpr step, ForKind kind,
                   SeqStmt body, ffi::Map<ffi::String, ffi::Any> annotations = {},
                   Location loc = UnknownLoc());

  explicit For(ffi::ObjectPtr<ForObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(For, Stmt, ForObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(ForObj);
};

class WhileObj : public StmtObj {
 public:
  explicit WhileObj(ffi::UnsafeInit tag) : condition(tag), body(tag) {}

  WhileObj(PrimExpr condition, SeqStmt body)
      : condition(std::move(condition)), body(std::move(body)) {}

  PrimExpr condition;
  SeqStmt body;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<WhileObj>()
        .def_ro("condition", &WhileObj::condition)
        .def_ro("body", &WhileObj::body);
  }
  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.While", WhileObj, StmtObj);
};

class While : public Stmt {
 public:
  TVM_TIRX_DLL While(PrimExpr condition, SeqStmt body, Location loc = UnknownLoc());

  explicit While(ffi::ObjectPtr<WhileObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(While, Stmt, WhileObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(WhileObj);
};

class ReturnObj : public StmtObj {
 public:
  explicit ReturnObj(ffi::UnsafeInit tag) : value(tag) {}

  explicit ReturnObj(Expr value) : value(std::move(value)) {}

  Expr value;

  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<ReturnObj>().def_ro("value", &ReturnObj::value);
  }

  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Return", ReturnObj, StmtObj);
};

class Return : public Stmt {
 public:
  TVM_TIRX_DLL explicit Return(Expr value, Location loc = UnknownLoc());

  explicit Return(ffi::ObjectPtr<ReturnObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Return, Stmt, ReturnObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(ReturnObj);
};

class BreakObj : public StmtObj {
 public:
  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<BreakObj>();
  }

  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Break", BreakObj, StmtObj);
};

class Break : public Stmt {
 public:
  TVM_TIRX_DLL explicit Break(Location loc);

  explicit Break(ffi::ObjectPtr<BreakObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Break, Stmt, BreakObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(BreakObj);
};

class ContinueObj : public StmtObj {
 public:
  static void RegisterReflection() {
    namespace refl = tvm::ffi::reflection;
    refl::ObjectDef<ContinueObj>();
  }

  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("ir.Continue", ContinueObj, StmtObj);
};

class Continue : public Stmt {
 public:
  TVM_TIRX_DLL explicit Continue(Location loc);

  explicit Continue(ffi::ObjectPtr<ContinueObj> node) : Stmt(std::move(node)) {}

  TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Continue, Stmt, ContinueObj);
  TVM_DEFINE_OBJECT_REF_COW_METHOD(ContinueObj);
};

// overload printing of for type.
TVM_TIRX_DLL std::ostream& operator<<(std::ostream& os, ForKind kind);

// inline implementations
inline const char* ForKind2String(ForKind t) {
  switch (t) {
    case ForKind::kDefault:
      return "serial";
    case ForKind::kParallel:
      return "parallel";
    case ForKind::kVectorized:
      return "vectorized";
    case ForKind::kUnrolled:
      return "unroll";
  }
  TVM_FFI_THROW(InternalError) << "Unknown ForKind" << t;
  TVM_FFI_UNREACHABLE();
}

}  // namespace tvm
#endif  // TVM_IR_STMT_H_