tvm
Loading...
Searching...
No Matches
doc_translator.h
Go to the documentation of this file.
1/*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19#ifndef TVM_SCRIPT_PRINTER_DOC_TRANSLATOR_H_
20#define TVM_SCRIPT_PRINTER_DOC_TRANSLATOR_H_
21
22#include <tvm/ffi/container/dict.h>
23#include <tvm/ffi/container/list.h>
24#include <tvm/ffi/container/map.h>
25#include <tvm/ffi/expected.h>
26#include <tvm/ffi/reflection/accessor.h>
27#include <tvm/ir/expr.h>
29
30#include <optional>
31#include <utility>
32
33namespace tvm {
34
35namespace script {
36namespace printer {
37
38class DocTranslatorObj;
39
52 TVMFFIAny (*translate)(DocTranslatorObj* translator, ffi::AnyView value,
53 const ffi::Object* destination) noexcept;
60 TVMFFIAny (*alloc_id)(DocTranslatorObj* translator, ffi::AnyView hint) noexcept;
68 TVMFFIAny (*var_get_or_alloc_id)(DocTranslatorObj* translator, ffi::AnyView var,
69 bool explicit_def) noexcept;
75 TVMFFIAny (*get_implicit_defs)(DocTranslatorObj* translator) noexcept;
81 TVMFFIAny (*begin_var_scope)(DocTranslatorObj* translator) noexcept;
87 TVMFFIAny (*end_var_scope)(DocTranslatorObj* translator) noexcept;
88};
89
100using FDocTranslate = ffi::reflection::NativeFunctionView<ffi::Optional<ExprDoc>(
101 DocTranslatorObj* translator, ffi::AnyView value, const ffi::Object* destination)>;
102
120class DocTranslatorObj : public ffi::Object {
121 public:
130 ffi::Optional<ExprDoc> Translate(ffi::AnyView value,
131 const ffi::Optional<Var> bind_var = std::nullopt) {
132 auto result = ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<ffi::Optional<ExprDoc>>(
133 vtable_->translate(this, value,
134 bind_var.has_value() ? bind_var.value().get() : nullptr))
135 .value();
136 if (result.has_value()) {
137 if (const auto* origin = value.as<ffi::Object>()) {
138 RecordOrigin(result.value(), ffi::GetRef<ffi::ObjectRef>(origin));
139 }
140 }
141 return result;
142 }
148 void Emit(const Doc& doc, ffi::Optional<ffi::ObjectRef> origin = std::nullopt) {
149 CurrentScopeDocs().push_back(doc);
150 if (origin.has_value()) RecordOrigin(doc, origin.value());
151 }
152
159 IdDoc VarGetOrAllocId(const Var& var, bool explicit_def) {
160 return ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<IdDoc>(
161 vtable_->var_get_or_alloc_id(this, var, explicit_def))
162 .value();
163 }
169 IdDoc AllocId(const ffi::String& hint) {
170 return ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<IdDoc>(vtable_->alloc_id(this, hint))
171 .value();
172 }
177 ffi::Dict<Var, IdDoc> GetImplicitDefs() {
178 return ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<ffi::Dict<Var, IdDoc>>(
179 vtable_->get_implicit_defs(this))
180 .value();
181 }
182
190 template <typename T>
191 T GetExtraConfig(const ffi::String& name, T fallback) const {
192 auto it = extra_config_.find(name);
193 return it == extra_config_.end() ? fallback : (*it).second.as_or_throw<T>();
194 }
201 template <typename T>
202 T GetOrCreateExtraState(const ffi::String& name) {
203 auto it = extra_state_.find(name);
204 if (it != extra_state_.end()) return (*it).second.as_or_throw<T>();
205 T value{};
206 extra_state_.Set(name, value);
207 return value;
208 }
214 void SetExtraState(const ffi::String& name, std::optional<ffi::Any> value) {
215 if (value.has_value()) {
216 extra_state_.Set(name, std::move(value.value()));
217 } else {
218 extra_state_.erase(name);
219 }
220 }
221
226 ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<void>(vtable_->begin_var_scope(this)).value();
227 }
234 void EndVarScope() {
235 ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<void>(vtable_->end_var_scope(this)).value();
236 }
240 void BeginDocScope() { doc_scopes_.push_back(ffi::List<Doc>()); }
245 ffi::List<Doc> EndDocScope() {
246 auto docs = CurrentScopeDocs();
247 doc_scopes_.pop_back();
248 return docs;
249 }
254 ffi::List<Doc> CurrentScopeDocs() const {
255 TVM_FFI_CHECK(!doc_scopes_.empty(), ValueError)
256 << "printer emission requires a collection scope";
257 return doc_scopes_.back();
258 }
265 template <typename Callback>
266 ffi::List<Doc> WithDocScope(Callback&& callback) {
267 size_t depth = doc_scopes_.size();
269 try {
270 std::forward<Callback>(callback)();
271 TVM_FFI_CHECK(doc_scopes_.size() == depth + 1, ValueError)
272 << "printer unbalanced Doc collection scopes";
273 return EndDocScope();
274 } catch (...) {
275 while (doc_scopes_.size() > depth) doc_scopes_.pop_back();
276 throw;
277 }
278 }
279
284 ffi::Dict<Doc, ffi::ObjectRef> GetDocOrigins() const { return doc_origins_; }
290 void RecordOrigin(const Doc& doc, const ffi::ObjectRef& origin) { doc_origins_.Set(doc, origin); }
297 ffi::Optional<ExprDoc> DefaultTranslate(ffi::AnyView value,
298 const ffi::Object* destination = nullptr);
299
300 static constexpr bool _type_mutable = true;
301 TVM_FFI_DECLARE_OBJECT_INFO("script.printer.DocTranslator", DocTranslatorObj, ffi::Object);
302
303 protected:
309 explicit DocTranslatorObj(const DocTranslatorVTable* vtable,
310 ffi::Map<ffi::String, ffi::Any> extra_config = {})
311 : extra_config_(std::move(extra_config)), vtable_(vtable) {}
312
316 ffi::List<ffi::List<Doc>> doc_scopes_;
317
318 private:
323 ffi::Map<ffi::String, ffi::Any> extra_config_;
328 ffi::Dict<ffi::String, ffi::Any> extra_state_;
332 ffi::Dict<Doc, ffi::ObjectRef> doc_origins_;
336 const DocTranslatorVTable* vtable_;
337};
338
346inline ffi::Array<StmtDoc> ToStmtDocArray(const ffi::List<Doc>& docs) {
347 ffi::Array<StmtDoc> statements;
348 for (const auto& doc : docs) {
349 if (auto block = doc.as<StmtBlockDoc>()) {
350 for (const auto& stmt : block.value()->stmts) statements.push_back(stmt);
351 } else {
352 statements.push_back(doc.as_or_throw<StmtDoc>());
353 }
354 }
355 return statements;
356}
357
361class DocTranslator : public ffi::ObjectRef {
362 public:
368};
369
378 ffi::Dict<Doc, ffi::ObjectRef>* doc_origins = nullptr,
379 ffi::Map<ffi::String, ffi::Any> extra_config = {});
380
381namespace type_attr {
385inline constexpr const char* kDocTranslate = "__tvm_doc_translate__";
386} // namespace type_attr
387
388namespace op_attr {
392inline constexpr const char* kDocTranslateOpCall = "__tvm_doc_translate_op_call__";
393} // namespace op_attr
394
395inline ffi::Optional<ExprDoc> DocTranslatorObj::DefaultTranslate(ffi::AnyView value,
396 const ffi::Object* destination) {
397 static ffi::reflection::TypeAttrColumn column(tvm::script::printer::type_attr::kDocTranslate);
398 ffi::AnyView attr = column[value.type_index()];
399 if (attr.type_index() == ffi::TypeIndex::kTVMFFIOpaquePtr) {
400 return ffi::details::ExpectedUnsafe::MoveFromTVMFFIAny<ffi::Optional<ExprDoc>>(
401 reinterpret_cast<decltype(DocTranslatorVTable::translate)>(attr.cast<void*>())(
402 this, value, destination))
403 .value();
404 }
405 if (attr.type_index() == ffi::TypeIndex::kTVMFFIFunction) {
406 ffi::Any destination_arg = nullptr;
407 if (destination) destination_arg = ffi::GetRef<ffi::ObjectRef>(destination);
408 return attr.cast<ffi::Function>()
409 .CallExpected<ffi::Optional<ExprDoc>>(this, value, destination_arg)
410 .value();
411 }
412 TVM_FFI_THROW(TypeError) << (attr.type_index() == ffi::TypeIndex::kTVMFFINone
413 ? std::string("printer has no Doc hook for ") +
414 value.GetTypeKey()
415 : "printer Doc hook must be a native pointer or ffi.Function");
416}
417
418} // namespace printer
419} // namespace script
420} // namespace tvm
421
422#endif // TVM_SCRIPT_PRINTER_DOC_TRANSLATOR_H_
Managed reference to VarNode.
Definition expr.h:714
Eager translation context shared by registered hooks. Hooks construct Docs, use explicit lexical scop...
Definition doc_translator.h:120
ffi::Dict< Doc, ffi::ObjectRef > GetDocOrigins() const
Get the owned Doc-to-original-object associations.
Definition doc_translator.h:284
TVM_FFI_DECLARE_OBJECT_INFO("script.printer.DocTranslator", DocTranslatorObj, ffi::Object)
T GetExtraConfig(const ffi::String &name, T fallback) const
Read a typed extension option.
Definition doc_translator.h:191
ffi::Dict< Var, IdDoc > GetImplicitDefs()
Get the current variable scope's pending definitions.
Definition doc_translator.h:177
void SetExtraState(const ffi::String &name, std::optional< ffi::Any > value)
Replace or remove extension state.
Definition doc_translator.h:214
static constexpr bool _type_mutable
Definition doc_translator.h:300
DocTranslatorObj(const DocTranslatorVTable *vtable, ffi::Map< ffi::String, ffi::Any > extra_config={})
Initialize an engine's translation context.
Definition doc_translator.h:309
void RecordOrigin(const Doc &doc, const ffi::ObjectRef &origin)
Set a Doc's original IR object, replacing any previous association.
Definition doc_translator.h:290
T GetOrCreateExtraState(const ffi::String &name)
Get or initialize typed extension state.
Definition doc_translator.h:202
ffi::List< ffi::List< Doc > > doc_scopes_
Active Doc collections, independent of lexical variable scopes.
Definition doc_translator.h:316
void BeginVarScope()
Begin a lexical variable scope independent of Doc collection.
Definition doc_translator.h:225
ffi::List< Doc > EndDocScope()
Pop the latest Doc collection.
Definition doc_translator.h:245
ffi::Optional< ExprDoc > DefaultTranslate(ffi::AnyView value, const ffi::Object *destination=nullptr)
Dispatch directly to the registered native or packed hook.
Definition doc_translator.h:395
IdDoc AllocId(const ffi::String &hint)
Reserve a fresh identifier without mapping a variable.
Definition doc_translator.h:169
void Emit(const Doc &doc, ffi::Optional< ffi::ObjectRef > origin=std::nullopt)
Append a completed Doc and record its optional origin.
Definition doc_translator.h:148
ffi::List< Doc > WithDocScope(Callback &&callback)
Run a callback in a balanced Doc collection scope.
Definition doc_translator.h:266
void EndVarScope()
End the latest naming region, retaining the root region. Explicit local bindings expire....
Definition doc_translator.h:234
ffi::Optional< ExprDoc > Translate(ffi::AnyView value, const ffi::Optional< Var > bind_var=std::nullopt)
Translate a value with an optional pre-mapped binding variable.
Definition doc_translator.h:130
void BeginDocScope()
Push an empty Doc collection.
Definition doc_translator.h:240
ffi::List< Doc > CurrentScopeDocs() const
Get the current Doc collection without popping it.
Definition doc_translator.h:254
IdDoc VarGetOrAllocId(const Var &var, bool explicit_def)
Reuse or allocate a variable's stable identifier.
Definition doc_translator.h:159
Owning reference to a hook translation context.
Definition doc_translator.h:361
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(DocTranslator, ffi::ObjectRef, DocTranslatorObj)
Retain a translation context.
Reference type of DocNode.
Definition doc.h:77
Reference type of IdDocNode.
Definition doc.h:386
Reference type of StmtBlockDocNode.
Definition doc.h:212
Reference type of StmtDocNode.
Definition doc.h:182
Base expr nodes in TVM.
constexpr const char * kDocTranslateOpCall
Op-specific Call translation hook with the FDocTranslate contract.
Definition doc_translator.h:392
constexpr const char * kDocTranslate
Type attribute containing a native or packed translation hook.
Definition doc_translator.h:385
TVM_TIRX_DLL Doc DocTranslate(ffi::AnyView ir, ffi::Dict< Doc, ffi::ObjectRef > *doc_origins=nullptr, ffi::Map< ffi::String, ffi::Any > extra_config={})
Translate IR into a complete Doc including declarations and metadata setup.
ffi::reflection::NativeFunctionView< ffi::Optional< ExprDoc >(DocTranslatorObj *translator, ffi::AnyView value, const ffi::Object *destination)> FDocTranslate
Native translation hook with borrowed inputs and an owning result.
Definition doc_translator.h:101
ffi::Array< StmtDoc > ToStmtDocArray(const ffi::List< Doc > &docs)
Convert collected Docs to statements in their original order.
Definition doc_translator.h:346
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition attr.h:23
#define TVM_TIRX_DLL
Definition base.h:83
Engine callbacks borrowed for the translator's lifetime.
Definition doc_translator.h:43
TVMFFIAny(* begin_var_scope)(DocTranslatorObj *translator) noexcept
Begin a lexical variable scope.
Definition doc_translator.h:81
TVMFFIAny(* end_var_scope)(DocTranslatorObj *translator) noexcept
End the current lexical variable scope.
Definition doc_translator.h:87
TVMFFIAny(* translate)(DocTranslatorObj *translator, ffi::AnyView value, const ffi::Object *destination) noexcept
Translate a value with an optional pre-mapped destination.
Definition doc_translator.h:52
TVMFFIAny(* alloc_id)(DocTranslatorObj *translator, ffi::AnyView hint) noexcept
Reserve an identifier without mapping a variable.
Definition doc_translator.h:60
TVMFFIAny(* var_get_or_alloc_id)(DocTranslatorObj *translator, ffi::AnyView var, bool explicit_def) noexcept
Find or allocate a variable's identifier.
Definition doc_translator.h:68
TVMFFIAny(* get_implicit_defs)(DocTranslatorObj *translator) noexcept
Get the current variable scope's pending definitions.
Definition doc_translator.h:75