tvm
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/reflection/access_path.h>
23 #include <tvm/ffi/reflection/registry.h>
24 #include <tvm/ir/cast.h>
25 #include <tvm/ir/module.h>
26 #include <tvm/script/printer/doc.h>
28 
29 #include <string>
30 #include <unordered_map>
31 #include <unordered_set>
32 #include <utility>
33 #include <vector>
34 
35 namespace tvm {
36 namespace script {
37 namespace printer {
38 
40 
42 
43 class IRDocsifier;
44 class IRDocsifierNode;
45 
50 class FrameNode : public ffi::Object {
51  public:
53  ffi::Array<StmtDoc> stmts;
57  std::vector<std::function<void()>> callbacks;
58 
59  static void RegisterReflection() {
60  namespace refl = tvm::ffi::reflection;
61  refl::ObjectDef<FrameNode>().def_ro("stmts", &FrameNode::stmts);
62  }
63 
64  static constexpr const bool _type_mutable = true;
65  TVM_FFI_DECLARE_OBJECT_INFO("script.printer.Frame", FrameNode, ffi::Object);
66 
67  public:
68  virtual ~FrameNode() = default;
69 
74  template <typename TCallback>
75  void AddExitCallback(TCallback&& cb) {
76  callbacks.emplace_back(std::forward<TCallback>(cb));
77  }
84  void AddDispatchToken(const IRDocsifier& d, const ffi::String& token);
88  virtual void EnterWithScope();
92  virtual void ExitWithScope();
93 };
94 
98 class Frame : public ffi::ObjectRef {
99  protected:
100  Frame() = default;
101 
102  public:
103  virtual ~Frame() = default;
104 
106  void EnterWithScope() { get()->EnterWithScope(); }
107 
109  void ExitWithScope() { get()->ExitWithScope(); }
110 
112 };
113 
115 
122 class IRDocsifierNode : public ffi::Object {
123  public:
125  using DocCreator = std::function<ExprDoc()>;
127  struct VariableInfo {
131  ffi::Optional<ffi::String> name;
132  };
134  PrinterConfig cfg{ffi::UnsafeInit()};
139  ffi::Array<Frame> frames;
146  ffi::Array<ffi::String> dispatch_tokens;
148  std::unordered_map<ffi::ObjectRef, VariableInfo, ffi::ObjectPtrHash, ffi::ObjectPtrEqual>
151  std::unordered_map<ffi::String, ffi::Array<ffi::Any>> metadata;
153  std::unordered_map<ffi::String, ffi::Array<GlobalInfo>> global_infos;
155  std::unordered_set<ffi::String> defined_names;
157  std::unordered_map<const ffi::Object*, std::vector<const ffi::Object*>> common_prefix;
159  std::unordered_set<std::string> ir_usage;
160 
161  static void RegisterReflection() {
162  namespace refl = tvm::ffi::reflection;
163  refl::ObjectDef<IRDocsifierNode>()
164  .def_ro("frames", &IRDocsifierNode::frames)
165  .def_ro("dispatch_tokens", &IRDocsifierNode::dispatch_tokens);
166  }
167 
168  static constexpr const bool _type_mutable = true;
169  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, ffi::Object);
170 
171  public:
183  IdDoc Define(const ffi::ObjectRef& obj, const Frame& frame, const ffi::String& name_hint);
184 
201  void Define(const ffi::ObjectRef& obj, const Frame& frame, DocCreator doc_factory);
202 
209  ffi::Optional<ExprDoc> GetVarDoc(const ffi::ObjectRef& obj) const;
211  ExprDoc AddMetadata(const ffi::Any& obj);
216  void AddGlobalInfo(const ffi::String& name, const GlobalInfo& ginfo);
223  bool IsVarDefined(const ffi::ObjectRef& obj) const;
225  void RemoveVar(const ffi::ObjectRef& obj);
231  void SetCommonPrefix(const ffi::ObjectRef& root, ffi::TypedFunction<bool(ffi::ObjectRef)> is_var);
239  template <class TDoc = Doc>
240  inline TDoc AsDoc(const Any& obj, const AccessPath& path) const;
241 };
242 
246 class IRDocsifier : public ffi::ObjectRef {
247  public:
250  explicit IRDocsifier(const PrinterConfig& cfg);
252  TVM_DLL static FType& vtable();
253 
255 };
256 
258 
260  if (d != nullptr) {
261  d->frames.push_back(ffi::GetRef<Frame>(this));
262  }
263 }
264 
266  for (const std::function<void()>& callback : callbacks) {
267  callback();
268  }
269  callbacks.clear();
270  if (d != nullptr) {
271  d->frames.pop_back();
272  }
273 }
274 
275 template <class TDoc>
276 inline static void AddDocDecoration(const Doc& d, const ffi::ObjectRef& obj, const AccessPath& path,
277  const PrinterConfig& cfg) {
278  if (cfg->obj_to_annotate.count(obj)) {
279  if (const auto* stmt = d.as<StmtDocNode>()) {
280  if (stmt->comment.has_value()) {
281  stmt->comment = stmt->comment.value() + "\n" + cfg->obj_to_annotate.at(obj);
282  } else {
283  stmt->comment = cfg->obj_to_annotate.at(obj);
284  }
285  } else {
286  LOG(WARNING) << "Expect StmtDoc to be annotated for object " << obj << ", but got "
287  << Downcast<TDoc>(d)->_type_key;
288  }
289  }
290  for (const ffi::ObjectRef& o : cfg->obj_to_underline) {
291  if (o.same_as(obj)) {
292  cfg->path_to_underline.push_back(path);
293  }
294  }
295  for (const auto& pair : cfg->path_to_annotate) {
296  AccessPath p = pair.first;
297  ffi::String attn = pair.second;
298  if (p->IsPrefixOf(path) && path->IsPrefixOf(p)) {
299  if (const auto* stmt = d.as<StmtDocNode>()) {
300  if (stmt->comment.has_value()) {
301  stmt->comment = stmt->comment.value() + "\n" + attn;
302  } else {
303  stmt->comment = attn;
304  }
305  } else {
306  LOG(WARNING) << "Expect StmtDoc to be annotated at object path " << p << ", but got "
307  << Downcast<TDoc>(d)->_type_key;
308  }
309  }
310  }
311 }
312 
313 template <class TDoc>
314 inline TDoc IRDocsifierNode::AsDoc(const Any& value, const AccessPath& path) const {
315  switch (value.type_index()) {
316  case ffi::TypeIndex::kTVMFFINone:
317  return Downcast<TDoc>(LiteralDoc::None(path));
318  case ffi::TypeIndex::kTVMFFIBool:
319  return Downcast<TDoc>(LiteralDoc::Boolean(value.as<bool>().value(), path));
320  case ffi::TypeIndex::kTVMFFIInt:
321  return Downcast<TDoc>(LiteralDoc::Int(value.as<int64_t>().value(), path));
322  case ffi::TypeIndex::kTVMFFIFloat:
323  return Downcast<TDoc>(LiteralDoc::Float(value.as<double>().value(), path));
324  case ffi::TypeIndex::kTVMFFISmallStr:
325  case ffi::TypeIndex::kTVMFFIStr: {
326  std::string string_value = value.cast<std::string>();
327  bool has_multiple_lines = string_value.find_first_of('\n') != std::string::npos;
328  if (has_multiple_lines) {
329  Doc d = const_cast<IRDocsifierNode*>(this)->AddMetadata(string_value);
330  // TODO(tqchen): cross check AddDocDecoration
331  return Downcast<TDoc>(d);
332  }
333  return Downcast<TDoc>(LiteralDoc::Str(string_value, path));
334  }
335  case ffi::TypeIndex::kTVMFFIDataType:
336  return Downcast<TDoc>(LiteralDoc::DataType(value.as<runtime::DataType>().value(), path));
337  case ffi::TypeIndex::kTVMFFIDevice:
338  return Downcast<TDoc>(LiteralDoc::Device(value.as<DLDevice>().value(), path));
339  default: {
340  if (auto opt_obj = value.as<ffi::ObjectRef>()) {
341  ffi::ObjectRef obj = opt_obj.value();
342  Doc d = IRDocsifier::vtable()(dispatch_tokens.back(), obj, path,
343  ffi::GetRef<IRDocsifier>(this));
344  d->source_paths.push_back(path);
345  AddDocDecoration<TDoc>(d, obj, path, cfg);
346  return Downcast<TDoc>(d);
347  } else {
348  TVM_FFI_THROW(TypeError) << "Cannot handle Any type: `" << value.GetTypeKey() << "`";
349  TVM_FFI_UNREACHABLE();
350  }
351  }
352  }
353 }
354 
355 inline void FrameNode::AddDispatchToken(const IRDocsifier& d, const ffi::String& token) {
356  d->dispatch_tokens.push_back(token);
357  this->AddExitCallback([doc = d.get()]() { doc->dispatch_tokens.pop_back(); });
358 }
359 
360 } // namespace printer
361 } // namespace script
362 } // namespace tvm
363 
364 #endif // TVM_SCRIPT_PRINTER_IR_DOCSIFIER_H_
Value casting helpers.
Managed reference to GlobalInfoNode.
Definition: global_info.h:54
Definition: config.h:151
Runtime primitive data type.
Definition: data_type.h:45
Reference type of DocNode.
Definition: doc.h:86
Reference type of ExprDocNode.
Definition: doc.h:144
Definition: ir_docsifier.h:50
virtual void EnterWithScope()
Method that's called when Frame enters the scope.
Definition: ir_docsifier.h:259
static void RegisterReflection()
Definition: ir_docsifier.h:59
IRDocsifierNode * d
Definition: ir_docsifier.h:55
virtual void ExitWithScope()
Method that's called when Frame exits the scope.
Definition: ir_docsifier.h:265
void AddExitCallback(TCallback &&cb)
Add a callback function to be called when this frame exits.
Definition: ir_docsifier.h:75
TVM_FFI_DECLARE_OBJECT_INFO("script.printer.Frame", FrameNode, ffi::Object)
std::vector< std::function< void()> > callbacks
Definition: ir_docsifier.h:57
ffi::Array< StmtDoc > stmts
Definition: ir_docsifier.h:53
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:355
static constexpr const bool _type_mutable
Definition: ir_docsifier.h:64
Reference type of FrameNode.
Definition: ir_docsifier.h:98
void EnterWithScope()
Method that's called when Frame enters the scope.
Definition: ir_docsifier.h:106
virtual ~Frame()=default
void ExitWithScope()
Method that's called when Frame exits the scope.
Definition: ir_docsifier.h:109
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Frame, ffi::ObjectRef, FrameNode)
Dynamic dispatch functor based on AccessPath.
Definition: ir_docsifier_functor.h:42
IRDocsifier is the top-level interface in the IR->Doc process.
Definition: ir_docsifier.h:122
std::unordered_set< std::string > ir_usage
The IR usages for headers printing.
Definition: ir_docsifier.h:159
std::function< ExprDoc()> DocCreator
A function that creates the doc for a variable.
Definition: ir_docsifier.h:125
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:149
std::unordered_map< ffi::String, ffi::Array< ffi::Any > > metadata
Metadata printing.
Definition: ir_docsifier.h:151
TDoc AsDoc(const Any &obj, const AccessPath &path) const
Transform the input object into TDoc.
Definition: ir_docsifier.h:314
ffi::Optional< ExprDoc > GetVarDoc(const ffi::ObjectRef &obj) const
Get the doc for variable.
ffi::Array< Frame > frames
The stack of frames.
Definition: ir_docsifier.h:139
ffi::Array< ffi::String > dispatch_tokens
The stack of dispatch tokens.
Definition: ir_docsifier.h:146
std::unordered_set< ffi::String > defined_names
The variable names used already.
Definition: ir_docsifier.h:155
PrinterConfig cfg
The configuration of the printer.
Definition: ir_docsifier.h:134
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, ffi::Object)
static void RegisterReflection()
Definition: ir_docsifier.h:161
std::unordered_map< ffi::String, ffi::Array< GlobalInfo > > global_infos
GlobalInfo printing.
Definition: ir_docsifier.h:153
std::unordered_map< const ffi::Object *, std::vector< const ffi::Object * > > common_prefix
Common prefixes of variable usages.
Definition: ir_docsifier.h:157
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:168
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.
void RemoveVar(const ffi::ObjectRef &obj)
Remove the variable defined.
Reference type of IRDocsifierNode.
Definition: ir_docsifier.h:246
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:350
static LiteralDoc Boolean(bool v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent boolean.
Definition: doc.h:286
static LiteralDoc DataType(const runtime::DataType &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition: doc.h:310
static LiteralDoc Device(const DLDevice &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent device.
Definition: doc.h:319
static LiteralDoc Int(int64_t v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent integer.
Definition: doc.h:278
static LiteralDoc Float(double v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent float.
Definition: doc.h:294
static LiteralDoc None(const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent None/null/empty value.
Definition: doc.h:270
static LiteralDoc Str(const ffi::String &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition: doc.h:302
The base class of statement doc.
Definition: doc.h:167
IRModule that holds the functions and type definitions.
ffi::reflection::AccessPath AccessPath
Definition: doc.h:34
An object that builds and maintains block scope and StmtSref mapping for Dependence analysis.
Definition: analyzer.h:37
Information about a variable, including its optional name and its doc creator.
Definition: ir_docsifier.h:127
DocCreator creator
The creator.
Definition: ir_docsifier.h:129
ffi::Optional< ffi::String > name
The name of the variable.
Definition: ir_docsifier.h:131