chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
* 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_SCRIPT_IR_BUILDER_BASE_H_
|
||||
#define TVM_SCRIPT_IR_BUILDER_BASE_H_
|
||||
|
||||
#include <tvm/ffi/reflection/registry.h>
|
||||
#include <tvm/ir/expr.h>
|
||||
#include <tvm/ir/function.h>
|
||||
#include <tvm/ir/node_functor.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace tvm {
|
||||
namespace script {
|
||||
namespace ir_builder {
|
||||
|
||||
////////////////////////////// IRBuilderFrame //////////////////////////////
|
||||
|
||||
/*!
|
||||
* \brief A stack frame of the IRBuilder used to keep track of the current scope.
|
||||
* Furthermore, the information stored in each stack frame can be useful for context-dependent
|
||||
* IR construction.
|
||||
*
|
||||
* \example
|
||||
*
|
||||
* The `T::MatchBuffer` below adds an element in `PrimFuncNode::buffer_map`:
|
||||
*
|
||||
* \code {.cpp}
|
||||
*
|
||||
* using T = tvm::script::ir_builder::tirx;
|
||||
* With <PrimFuncFrame> _(...);
|
||||
* Buffer buffer = T::MatchBuffer(...);
|
||||
*
|
||||
* \endcode
|
||||
*
|
||||
* The `T::MatchBuffer` below instead generates `MatchBufferRegion` in a TIR block:
|
||||
*
|
||||
* \code {.cpp}
|
||||
*
|
||||
* using T = tvm::script::ir_builder::tirx;
|
||||
* With <PrimFuncFrame> _(...);
|
||||
* {
|
||||
* With<SBlockFrame> _2(...);
|
||||
* Buffer buffer = T::MatchBuffer(...);
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
class IRBuilderFrameNode : public ffi::Object {
|
||||
public:
|
||||
/*! \brief A list of callbacks used when exiting the frame. */
|
||||
std::vector<ffi::TypedFunction<void()>> callbacks;
|
||||
|
||||
static void RegisterReflection() {
|
||||
namespace refl = tvm::ffi::reflection;
|
||||
refl::ObjectDef<IRBuilderFrameNode>();
|
||||
// `callbacks` is not registered as it's not visited.
|
||||
}
|
||||
|
||||
static constexpr const bool _type_mutable = true;
|
||||
TVM_FFI_DECLARE_OBJECT_INFO("script.ir_builder.IRBuilderFrame", IRBuilderFrameNode, ffi::Object);
|
||||
|
||||
public:
|
||||
/*! \brief Default destructor. */
|
||||
virtual ~IRBuilderFrameNode() = default;
|
||||
/*!
|
||||
* \brief The method called when entering RAII scope.
|
||||
* \sa tvm::support::With
|
||||
*/
|
||||
virtual void EnterWithScope();
|
||||
/*!
|
||||
* \brief The method called when exiting RAII scope.
|
||||
* \sa tvm::support::With
|
||||
*/
|
||||
virtual void ExitWithScope();
|
||||
/*!
|
||||
* \brief Add a callback method invoked when exiting the RAII scope.
|
||||
* \param callback The callback to be added.
|
||||
*/
|
||||
void AddCallback(ffi::TypedFunction<void()> callback);
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Managed reference to an IRBuilderFrameNode.
|
||||
* \sa IRBuilderFrameNode
|
||||
*/
|
||||
class IRBuilderFrame : public ffi::ObjectRef {
|
||||
public:
|
||||
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IRBuilderFrame, ffi::ObjectRef, IRBuilderFrameNode);
|
||||
|
||||
protected:
|
||||
/*! \brief Disallow direct construction of this object. */
|
||||
IRBuilderFrame() = default;
|
||||
explicit IRBuilderFrame(ffi::ObjectPtr<IRBuilderFrameNode> data) : ffi::ObjectRef(data) {}
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Redirected to `IRBuilderFrameNode::EnterWithScope`.
|
||||
* \sa IRBuilderFrameNode::EnterWithScope
|
||||
*/
|
||||
inline void EnterWithScope() {
|
||||
TVM_FFI_ICHECK(data_ != nullptr);
|
||||
static_cast<IRBuilderFrameNode*>(data_.get())->EnterWithScope();
|
||||
}
|
||||
/*!
|
||||
* \brief Redirected to `IRBuilderFrameNode::ExitWithScope`.
|
||||
* \sa IRBuilderFrameNode::ExitWithScope
|
||||
*/
|
||||
inline void ExitWithScope() {
|
||||
TVM_FFI_ICHECK(data_ != nullptr);
|
||||
static_cast<IRBuilderFrameNode*>(data_.get())->ExitWithScope();
|
||||
data_.reset();
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////// IRBuilder //////////////////////////////
|
||||
|
||||
/*!
|
||||
* \brief A dialect-agnostic IRBuilder that constructs any IR of TVM.
|
||||
* An idiomatic use of this class is to put this inside the RAII with-scope,
|
||||
* call dialect-specific methods accordingly. Upon exiting the scope.
|
||||
*
|
||||
* \code
|
||||
*
|
||||
* PrimFunc ConstructPrimFunc() {
|
||||
* using tvm::script::ir_builder::IRBuilder;
|
||||
* using T = tvm::script::ir_builder::tirx;
|
||||
* IRBuilder builder;
|
||||
* // Step 1. Place IRBuilder inside the with-scope.
|
||||
* {
|
||||
* With<IRBuilder> _(builder);
|
||||
* // Step 2. Call dialect-specific methods.
|
||||
* With<T::PrimFuncFrame> _2(...);
|
||||
* T::MatchBuffer(...);
|
||||
* }
|
||||
* // Step 3. Return the constructed PrimFunc.
|
||||
* return builder->Get<PrimFunc>();
|
||||
* }
|
||||
*
|
||||
* \endcode
|
||||
*/
|
||||
class IRBuilderNode : public ffi::Object {
|
||||
public:
|
||||
/*! \brief A stack of context frames in the IRBuilder */
|
||||
ffi::Array<IRBuilderFrame> frames;
|
||||
/*! \brief The outcome of IR construction */
|
||||
ffi::Optional<ffi::ObjectRef> result;
|
||||
|
||||
static void RegisterReflection() {
|
||||
namespace refl = tvm::ffi::reflection;
|
||||
refl::ObjectDef<IRBuilderNode>()
|
||||
.def_ro("frames", &IRBuilderNode::frames)
|
||||
.def_ro("result", &IRBuilderNode::result);
|
||||
}
|
||||
|
||||
static constexpr const bool _type_mutable = true;
|
||||
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.ir_builder.IRBuilder", IRBuilderNode, ffi::Object);
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Find a frame of the given type in the stack `this->frames` from top to bottom.
|
||||
* \tparam T The type of the frame to find.
|
||||
* \return The frame if found, otherwise std::nullopt.
|
||||
*/
|
||||
template <typename TFrame>
|
||||
inline ffi::Optional<TFrame> FindFrame() const;
|
||||
/*!
|
||||
* \brief Get the frame on top of the stack `this->frames` if its type is `TFrame`.
|
||||
* \tparam TFrame The assumed type of the last frame on stack.
|
||||
* \return The frame if the stack is non-empty and the top of the stack is of type `TFrame`.
|
||||
* Otherwise std::nullopt.
|
||||
*/
|
||||
template <typename TFrame>
|
||||
inline ffi::Optional<TFrame> GetLastFrame() const;
|
||||
/*!
|
||||
* \brief Get the IR being constructed.
|
||||
* \tparam TObjectRef The type of the IR being constructed.
|
||||
* \return The resulting IR. Throw an exception if the IR is not constructed yet.
|
||||
*/
|
||||
template <typename TObjectRef>
|
||||
inline TObjectRef Get() const;
|
||||
};
|
||||
|
||||
/*!
|
||||
* \brief Managed reference to an IRBuilderNode.
|
||||
* \sa IRBuilderNode
|
||||
*/
|
||||
class IRBuilder : public ffi::ObjectRef {
|
||||
public:
|
||||
/*! \brief Creates an IRBuilder. */
|
||||
IRBuilder();
|
||||
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IRBuilder, ffi::ObjectRef, IRBuilderNode);
|
||||
|
||||
public:
|
||||
/*!
|
||||
* \brief Puts the current IRBuilder into a thread-local scope, which can be retrieved using
|
||||
* `IRBuilder::Current()`.
|
||||
*
|
||||
* \code {.cpp}
|
||||
* IRBuilder builder;
|
||||
* {
|
||||
* With<IRBuilder> _(builder);
|
||||
* // IRBuilder::Current() == builder
|
||||
* }
|
||||
* // IRBuilder::Current() == nullptr
|
||||
* \endcode
|
||||
*
|
||||
* \sa IRBuilder::Current
|
||||
* \sa IRBuilder::ExitWithScope
|
||||
* \sa tvm::support::With
|
||||
*/
|
||||
void EnterWithScope();
|
||||
/*!
|
||||
* \brief Exit the RAII scope.
|
||||
* \sa IRBuilder::EnterWithScope
|
||||
* \sa IRBuilder::Current
|
||||
* \sa tvm::support::With
|
||||
*/
|
||||
void ExitWithScope();
|
||||
/*!
|
||||
* \brief Get the current IRBuilder in the current thread-local scope.
|
||||
* \return The current IRBuilder.
|
||||
* \sa IRBuilder::EnterWithScope
|
||||
* \sa IRBuilder::ExitWithScope
|
||||
* \sa tvm::support::With
|
||||
*/
|
||||
static IRBuilder Current();
|
||||
/*! \brief See if the current thread-local scope has an IRBuilder. */
|
||||
static bool IsInScope();
|
||||
/*!
|
||||
* \brief Give a string name to the `obj`
|
||||
* \tparam TObjectRef The type of the object to name.
|
||||
* \param name The name to give to the object.
|
||||
* \param obj The object to name.
|
||||
*/
|
||||
template <class TObjectRef>
|
||||
inline static TObjectRef Name(ffi::String name, TObjectRef obj);
|
||||
};
|
||||
|
||||
////////////////////////////// Details //////////////////////////////
|
||||
|
||||
namespace details {
|
||||
|
||||
class Namer {
|
||||
public:
|
||||
using FType = NodeFunctor<void(const ffi::ObjectRef&, ffi::String)>;
|
||||
static FType& vtable();
|
||||
static void Name(ffi::ObjectRef node, ffi::String name);
|
||||
};
|
||||
|
||||
} // namespace details
|
||||
|
||||
template <class TObjectRef>
|
||||
inline TObjectRef IRBuilder::Name(ffi::String name, TObjectRef obj) {
|
||||
details::Namer::Name(obj, name);
|
||||
return obj.template as_or_throw<TObjectRef>();
|
||||
}
|
||||
|
||||
template <typename TFrame>
|
||||
inline ffi::Optional<TFrame> IRBuilderNode::FindFrame() const {
|
||||
using TFrameNode = typename TFrame::ContainerType;
|
||||
for (auto it = frames.rbegin(); it != frames.rend(); ++it) {
|
||||
if (const TFrameNode* p = (*it).template as<TFrameNode>()) {
|
||||
return ffi::GetRef<TFrame>(p);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename TFrame>
|
||||
inline ffi::Optional<TFrame> IRBuilderNode::GetLastFrame() const {
|
||||
using TFrameNode = typename TFrame::ContainerType;
|
||||
if (!frames.empty() && frames.back()->IsInstance<TFrameNode>()) {
|
||||
return frames.back().as_or_throw<TFrame>();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
template <typename TObjectRef>
|
||||
inline TObjectRef IRBuilderNode::Get() const {
|
||||
using TObject = typename TObjectRef::ContainerType;
|
||||
TVM_FFI_CHECK(result.has_value(), IndexError) << "No result exists in IRBuilder yet";
|
||||
const auto* n = result.as<TObject>();
|
||||
TVM_FFI_CHECK(n != nullptr, TypeError)
|
||||
<< "IRBuilder result is not of type: " << TObject::_type_key;
|
||||
return ffi::GetRef<TObjectRef>(n);
|
||||
}
|
||||
|
||||
} // namespace ir_builder
|
||||
} // namespace script
|
||||
} // namespace tvm
|
||||
|
||||
#endif // TVM_SCRIPT_IR_BUILDER_BASE_H_
|
||||
Reference in New Issue
Block a user