tvm
Loading...
Searching...
No Matches
ir_docsifier.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_IR_DOCSIFIER_H_
20#define TVM_SCRIPT_PRINTER_IR_DOCSIFIER_H_
21
22#include <tvm/ffi/device.h>
23#include <tvm/ffi/reflection/access_path.h>
24#include <tvm/ffi/reflection/registry.h>
25#include <tvm/ir/module.h>
29
30#include <string>
31#include <unordered_map>
32#include <unordered_set>
33#include <utility>
34#include <vector>
35
36namespace tvm {
37namespace script {
38namespace printer {
39
40using AccessPath = ffi::reflection::AccessPath;
41
43
44class IRDocsifier;
45class IRDocsifierNode;
46
51class FrameNode : public ffi::Object {
52 public:
54 ffi::Array<StmtDoc> stmts;
58 std::vector<std::function<void()>> callbacks;
59
60 static void RegisterReflection() {
61 namespace refl = tvm::ffi::reflection;
62 refl::ObjectDef<FrameNode>().def_ro("stmts", &FrameNode::stmts);
63 }
64
65 static constexpr const bool _type_mutable = true;
66 TVM_FFI_DECLARE_OBJECT_INFO("script.printer.Frame", FrameNode, ffi::Object);
67
68 public:
69 virtual ~FrameNode() = default;
70
75 template <typename TCallback>
77 callbacks.emplace_back(std::forward<TCallback>(cb));
78 }
85 void AddDispatchToken(const IRDocsifier& d, const ffi::String& token);
89 virtual void EnterWithScope();
93 virtual void ExitWithScope();
94};
95
99class Frame : public ffi::ObjectRef {
100 protected:
101 Frame() = default;
102
103 public:
104 virtual ~Frame() = default;
105
107 void EnterWithScope() { get()->EnterWithScope(); }
108
110 void ExitWithScope() { get()->ExitWithScope(); }
111
113};
114
116
123class IRDocsifierNode : public ffi::Object {
124 public:
126 using DocCreator = std::function<ExprDoc()>;
132 ffi::Optional<ffi::String> name;
133 };
135 PrinterConfig cfg{ffi::UnsafeInit()};
140 ffi::Array<Frame> frames;
147 ffi::Array<ffi::String> dispatch_tokens;
149 std::unordered_map<ffi::ObjectRef, VariableInfo, ffi::ObjectPtrHash, ffi::ObjectPtrEqual>
152 std::unordered_map<ffi::String, ffi::Array<ffi::Any>> metadata;
154 std::unordered_map<ffi::String, ffi::Array<GlobalInfo>> global_infos;
156 std::unordered_set<ffi::String> defined_names;
158 std::unordered_map<const ffi::Object*, std::vector<const ffi::Object*>> common_prefix;
160 std::unordered_set<std::string> ir_usage;
161
162 static void RegisterReflection() {
163 namespace refl = tvm::ffi::reflection;
164 refl::ObjectDef<IRDocsifierNode>()
165 .def_ro("frames", &IRDocsifierNode::frames)
166 .def_ro("dispatch_tokens", &IRDocsifierNode::dispatch_tokens);
167 }
168
169 static constexpr const bool _type_mutable = true;
170 TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, ffi::Object);
171
172 public:
184 IdDoc Define(const ffi::ObjectRef& obj, const Frame& frame, const ffi::String& name_hint);
185
202 void Define(const ffi::ObjectRef& obj, const Frame& frame, DocCreator doc_factory);
203
210 ffi::Optional<ExprDoc> GetVarDoc(const ffi::ObjectRef& obj) const;
212 ExprDoc AddMetadata(const ffi::Any& obj);
217 void AddGlobalInfo(const ffi::String& name, const GlobalInfo& ginfo);
224 bool IsVarDefined(const ffi::ObjectRef& obj) const;
226 void RemoveVar(const ffi::ObjectRef& obj);
232 void SetCommonPrefix(const ffi::ObjectRef& root, ffi::TypedFunction<bool(ffi::ObjectRef)> is_var);
240 template <class TDoc = Doc>
241 inline TDoc AsDoc(const Any& obj, const AccessPath& path) const;
242};
243
257
259
261 if (d != nullptr) {
262 d->frames.push_back(ffi::GetRef<Frame>(this));
263 }
264}
265
267 for (const std::function<void()>& callback : callbacks) {
268 callback();
269 }
270 callbacks.clear();
271 if (d != nullptr) {
272 d->frames.pop_back();
273 }
274}
275
276template <class TDoc>
277inline static void AddDocDecoration(const Doc& d, const ffi::ObjectRef& obj, const AccessPath& path,
278 const PrinterConfig& cfg) {
279 if (cfg->obj_to_annotate.count(obj)) {
280 if (const auto* stmt = d.as<StmtDocNode>()) {
281 if (stmt->comment.has_value()) {
282 stmt->comment = stmt->comment.value() + "\n" + cfg->obj_to_annotate.at(obj);
283 } else {
284 stmt->comment = cfg->obj_to_annotate.at(obj);
285 }
286 } else {
287 LOG(WARNING) << "Expect StmtDoc to be annotated for object " << obj << ", but got "
288 << d.as_or_throw<TDoc>()->_type_key;
289 }
290 }
291 for (const ffi::ObjectRef& o : cfg->obj_to_underline) {
292 if (o.same_as(obj)) {
293 cfg->path_to_underline.push_back(path);
294 }
295 }
296 for (const auto& pair : cfg->path_to_annotate) {
297 AccessPath p = pair.first;
298 ffi::String attn = pair.second;
299 if (p->IsPrefixOf(path) && path->IsPrefixOf(p)) {
300 if (const auto* stmt = d.as<StmtDocNode>()) {
301 if (stmt->comment.has_value()) {
302 stmt->comment = stmt->comment.value() + "\n" + attn;
303 } else {
304 stmt->comment = attn;
305 }
306 } else {
307 LOG(WARNING) << "Expect StmtDoc to be annotated at object path " << p << ", but got "
308 << d.as_or_throw<TDoc>()->_type_key;
309 }
310 }
311 }
312}
313
314template <class TDoc>
315inline TDoc IRDocsifierNode::AsDoc(const Any& value, const AccessPath& path) const {
316 switch (value.type_index()) {
317 case ffi::TypeIndex::kTVMFFINone:
318 return LiteralDoc::None(path).as_or_throw<TDoc>();
319 case ffi::TypeIndex::kTVMFFIBool:
320 return LiteralDoc::Boolean(value.as<bool>().value(), path).as_or_throw<TDoc>();
321 case ffi::TypeIndex::kTVMFFIInt:
322 return LiteralDoc::Int(value.as<int64_t>().value(), path).as_or_throw<TDoc>();
323 case ffi::TypeIndex::kTVMFFIFloat:
324 return LiteralDoc::Float(value.as<double>().value(), path).as_or_throw<TDoc>();
325 case ffi::TypeIndex::kTVMFFISmallStr:
326 case ffi::TypeIndex::kTVMFFIStr: {
327 std::string string_value = value.cast<std::string>();
328 bool has_multiple_lines = string_value.find_first_of('\n') != std::string::npos;
329 if (has_multiple_lines) {
330 Doc d = const_cast<IRDocsifierNode*>(this)->AddMetadata(string_value);
331 // TODO(tqchen): cross check AddDocDecoration
332 return d.as_or_throw<TDoc>();
333 }
334 return LiteralDoc::Str(string_value, path).as_or_throw<TDoc>();
335 }
336 case ffi::TypeIndex::kTVMFFIDataType:
337 return LiteralDoc::DataType(value.as<DLDataType>().value(), path).as_or_throw<TDoc>();
338 case ffi::TypeIndex::kTVMFFIDevice:
339 return LiteralDoc::Device(value.as<DLDevice>().value(), path).as_or_throw<TDoc>();
340 default: {
341 if (auto opt_obj = value.as<ffi::ObjectRef>()) {
342 ffi::ObjectRef obj = opt_obj.value();
343 Doc d = IRDocsifier::vtable()(dispatch_tokens.back(), obj, path,
344 ffi::GetRef<IRDocsifier>(this));
345 d->source_paths.push_back(path);
346 AddDocDecoration<TDoc>(d, obj, path, cfg);
347 return d.as_or_throw<TDoc>();
348 } else {
349 TVM_FFI_THROW(TypeError) << "Cannot handle Any type: `" << value.GetTypeKey() << "`";
351 }
352 }
353 }
354}
355
356inline void FrameNode::AddDispatchToken(const IRDocsifier& d, const ffi::String& token) {
357 d->dispatch_tokens.push_back(token);
358 this->AddExitCallback([doc = d.get()]() { doc->dispatch_tokens.pop_back(); });
359}
360
361} // namespace printer
362} // namespace script
363} // namespace tvm
364
365#endif // TVM_SCRIPT_PRINTER_IR_DOCSIFIER_H_
Managed reference to GlobalInfoNode.
Definition global_info.h:54
Definition config.h:146
RAII wrapper function to enter and exit a context object similar to python's with syntax.
Definition with_context.h:59
Reference type of DocNode.
Definition doc.h:88
Reference type of ExprDocNode.
Definition doc.h:146
Definition ir_docsifier.h:51
virtual void EnterWithScope()
Method that's called when Frame enters the scope.
Definition ir_docsifier.h:260
static void RegisterReflection()
Definition ir_docsifier.h:60
IRDocsifierNode * d
Definition ir_docsifier.h:56
virtual void ExitWithScope()
Method that's called when Frame exits the scope.
Definition ir_docsifier.h:266
void AddExitCallback(TCallback &&cb)
Add a callback function to be called when this frame exits.
Definition ir_docsifier.h:76
TVM_FFI_DECLARE_OBJECT_INFO("script.printer.Frame", FrameNode, ffi::Object)
std::vector< std::function< void()> > callbacks
Definition ir_docsifier.h:58
ffi::Array< StmtDoc > stmts
Definition ir_docsifier.h:54
void AddDispatchToken(const IRDocsifier &d, const ffi::String &token)
Add a dispatch token to the docsifier, and a callback that pops the token when this frame exits.
Definition ir_docsifier.h:356
static constexpr const bool _type_mutable
Definition ir_docsifier.h:65
Reference type of FrameNode.
Definition ir_docsifier.h:99
void EnterWithScope()
Method that's called when Frame enters the scope.
Definition ir_docsifier.h:107
virtual ~Frame()=default
void ExitWithScope()
Method that's called when Frame exits the scope.
Definition ir_docsifier.h:110
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Frame, ffi::ObjectRef, FrameNode)
IRDocsifier is the top-level interface in the IR->Doc process.
Definition ir_docsifier.h:123
std::unordered_set< std::string > ir_usage
The IR usages for headers printing.
Definition ir_docsifier.h:160
std::function< ExprDoc()> DocCreator
A function that creates the doc for a variable.
Definition ir_docsifier.h:126
IdDoc Define(const ffi::ObjectRef &obj, const Frame &frame, const ffi::String &name_hint)
Define variable by name.
bool IsVarDefined(const ffi::ObjectRef &obj) const
Check if a variable exists in the table.
ExprDoc AddMetadata(const ffi::Any &obj)
Add a TVM object to the metadata section.
std::unordered_map< ffi::ObjectRef, VariableInfo, ffi::ObjectPtrHash, ffi::ObjectPtrEqual > obj2info
Mapping from a var to its info.
Definition ir_docsifier.h:150
std::unordered_map< ffi::String, ffi::Array< ffi::Any > > metadata
Metadata printing.
Definition ir_docsifier.h:152
TDoc AsDoc(const Any &obj, const AccessPath &path) const
Transform the input object into TDoc.
Definition ir_docsifier.h:315
ffi::Array< Frame > frames
The stack of frames.
Definition ir_docsifier.h:140
ffi::Array< ffi::String > dispatch_tokens
The stack of dispatch tokens.
Definition ir_docsifier.h:147
std::unordered_set< ffi::String > defined_names
The variable names used already.
Definition ir_docsifier.h:156
PrinterConfig cfg
The configuration of the printer.
Definition ir_docsifier.h:135
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, ffi::Object)
static void RegisterReflection()
Definition ir_docsifier.h:162
std::unordered_map< ffi::String, ffi::Array< GlobalInfo > > global_infos
GlobalInfo printing.
Definition ir_docsifier.h:154
std::unordered_map< const ffi::Object *, std::vector< const ffi::Object * > > common_prefix
Common prefixes of variable usages.
Definition ir_docsifier.h:158
void SetCommonPrefix(const ffi::ObjectRef &root, ffi::TypedFunction< bool(ffi::ObjectRef)> is_var)
Set the common prefix information of variable usage.
static constexpr const bool _type_mutable
Definition ir_docsifier.h:169
void Define(const ffi::ObjectRef &obj, const Frame &frame, DocCreator doc_factory)
Define variable by doc factory.
void AddGlobalInfo(const ffi::String &name, const GlobalInfo &ginfo)
Add a GlobalInfo to the global_infos map.
ffi::Optional< ExprDoc > GetVarDoc(const ffi::ObjectRef &obj) const
Get the doc for variable.
void RemoveVar(const ffi::ObjectRef &obj)
Remove the variable defined.
Reference type of IRDocsifierNode.
Definition ir_docsifier.h:247
static FType & vtable()
The registration table for IRDocsifier.
IRDocsifier(const PrinterConfig &cfg)
Create a IRDocsifier.
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IRDocsifier, ffi::ObjectRef, IRDocsifierNode)
Reference type of IdDocNode.
Definition doc.h:387
static LiteralDoc DataType(DLDataType v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition doc.h:312
static LiteralDoc Boolean(bool v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent boolean.
Definition doc.h:288
static LiteralDoc Device(const DLDevice &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent device.
Definition doc.h:322
static LiteralDoc Int(int64_t v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent integer.
Definition doc.h:280
static LiteralDoc Float(double v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent float.
Definition doc.h:296
static LiteralDoc None(const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent None/null/empty value.
Definition doc.h:272
static LiteralDoc Str(const ffi::String &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition doc.h:304
The base class of statement doc.
Definition doc.h:169
Configuration object for the TVMScript printer.
IRModule that holds the functions and type definitions.
ffi::reflection::AccessPath AccessPath
Definition doc.h:36
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition analyzer.h:40
Information about a variable, including its optional name and its doc creator.
Definition ir_docsifier.h:128
DocCreator creator
The creator.
Definition ir_docsifier.h:130
ffi::Optional< ffi::String > name
The name of the variable.
Definition ir_docsifier.h:132