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/module.h>
25 #include <tvm/node/node.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 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, 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 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 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<ObjectRef, VariableInfo, ObjectPtrHash, ObjectPtrEqual> obj2info;
150  std::unordered_map<ffi::String, ffi::Array<ffi::Any>> metadata;
152  std::unordered_map<ffi::String, ffi::Array<GlobalInfo>> global_infos;
154  std::unordered_set<ffi::String> defined_names;
156  std::unordered_map<const Object*, std::vector<const Object*>> common_prefix;
158  std::unordered_set<std::string> ir_usage;
159 
160  static void RegisterReflection() {
161  namespace refl = tvm::ffi::reflection;
162  refl::ObjectDef<IRDocsifierNode>()
163  .def_ro("frames", &IRDocsifierNode::frames)
164  .def_ro("dispatch_tokens", &IRDocsifierNode::dispatch_tokens);
165  }
166 
167  static constexpr const bool _type_mutable = true;
168  TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, Object);
169 
170  public:
182  IdDoc Define(const ObjectRef& obj, const Frame& frame, const ffi::String& name_hint);
183 
200  void Define(const ObjectRef& obj, const Frame& frame, DocCreator doc_factory);
201 
208  ffi::Optional<ExprDoc> GetVarDoc(const ObjectRef& obj) const;
210  ExprDoc AddMetadata(const ffi::Any& obj);
215  void AddGlobalInfo(const ffi::String& name, const GlobalInfo& ginfo);
222  bool IsVarDefined(const ObjectRef& obj) const;
224  void RemoveVar(const ObjectRef& obj);
230  void SetCommonPrefix(const ObjectRef& root, ffi::TypedFunction<bool(ObjectRef)> is_var);
238  template <class TDoc = Doc>
239  inline TDoc AsDoc(const Any& obj, const AccessPath& path) const;
240 };
241 
245 class IRDocsifier : public ObjectRef {
246  public:
249  explicit IRDocsifier(const PrinterConfig& cfg);
251  TVM_DLL static FType& vtable();
252 
254 };
255 
257 
259  if (d != nullptr) {
260  d->frames.push_back(ffi::GetRef<Frame>(this));
261  }
262 }
263 
265  for (const std::function<void()>& callback : callbacks) {
266  callback();
267  }
268  callbacks.clear();
269  if (d != nullptr) {
270  d->frames.pop_back();
271  }
272 }
273 
274 template <class TDoc>
275 inline static void AddDocDecoration(const Doc& d, const ObjectRef& obj, const AccessPath& path,
276  const PrinterConfig& cfg) {
277  if (cfg->obj_to_annotate.count(obj)) {
278  if (const auto* stmt = d.as<StmtDocNode>()) {
279  if (stmt->comment.has_value()) {
280  stmt->comment = stmt->comment.value() + "\n" + cfg->obj_to_annotate.at(obj);
281  } else {
282  stmt->comment = cfg->obj_to_annotate.at(obj);
283  }
284  } else {
285  LOG(WARNING) << "Expect StmtDoc to be annotated for object " << obj << ", but got "
286  << Downcast<TDoc>(d)->_type_key;
287  }
288  }
289  for (const ObjectRef& o : cfg->obj_to_underline) {
290  if (o.same_as(obj)) {
291  cfg->path_to_underline.push_back(path);
292  }
293  }
294  for (const auto& pair : cfg->path_to_annotate) {
295  AccessPath p = pair.first;
296  ffi::String attn = pair.second;
297  if (p->IsPrefixOf(path) && path->IsPrefixOf(p)) {
298  if (const auto* stmt = d.as<StmtDocNode>()) {
299  if (stmt->comment.has_value()) {
300  stmt->comment = stmt->comment.value() + "\n" + attn;
301  } else {
302  stmt->comment = attn;
303  }
304  } else {
305  LOG(WARNING) << "Expect StmtDoc to be annotated at object path " << p << ", but got "
306  << Downcast<TDoc>(d)->_type_key;
307  }
308  }
309  }
310 }
311 
312 template <class TDoc>
313 inline TDoc IRDocsifierNode::AsDoc(const Any& value, const AccessPath& path) const {
314  switch (value.type_index()) {
315  case ffi::TypeIndex::kTVMFFINone:
316  return Downcast<TDoc>(LiteralDoc::None(path));
317  case ffi::TypeIndex::kTVMFFIBool:
318  return Downcast<TDoc>(LiteralDoc::Boolean(value.as<bool>().value(), path));
319  case ffi::TypeIndex::kTVMFFIInt:
320  return Downcast<TDoc>(LiteralDoc::Int(value.as<int64_t>().value(), path));
321  case ffi::TypeIndex::kTVMFFIFloat:
322  return Downcast<TDoc>(LiteralDoc::Float(value.as<double>().value(), path));
323  case ffi::TypeIndex::kTVMFFISmallStr:
324  case ffi::TypeIndex::kTVMFFIStr: {
325  std::string string_value = value.cast<std::string>();
326  bool has_multiple_lines = string_value.find_first_of('\n') != std::string::npos;
327  if (has_multiple_lines) {
328  Doc d = const_cast<IRDocsifierNode*>(this)->AddMetadata(string_value);
329  // TODO(tqchen): cross check AddDocDecoration
330  return Downcast<TDoc>(d);
331  }
332  return Downcast<TDoc>(LiteralDoc::Str(string_value, path));
333  }
334  case ffi::TypeIndex::kTVMFFIDataType:
335  return Downcast<TDoc>(LiteralDoc::DataType(value.as<runtime::DataType>().value(), path));
336  case ffi::TypeIndex::kTVMFFIDevice:
337  return Downcast<TDoc>(LiteralDoc::Device(value.as<DLDevice>().value(), path));
338  default: {
339  if (auto opt_obj = value.as<ObjectRef>()) {
340  ObjectRef obj = opt_obj.value();
341  Doc d = IRDocsifier::vtable()(dispatch_tokens.back(), obj, path,
342  ffi::GetRef<IRDocsifier>(this));
343  d->source_paths.push_back(path);
344  AddDocDecoration<TDoc>(d, obj, path, cfg);
345  return Downcast<TDoc>(d);
346  } else {
347  LOG(FATAL) << "TypeError: Cannot handle Any type: `" << value.GetTypeKey() << "`";
348  TVM_FFI_UNREACHABLE();
349  }
350  }
351  }
352 }
353 
354 inline void FrameNode::AddDispatchToken(const IRDocsifier& d, const ffi::String& token) {
355  d->dispatch_tokens.push_back(token);
356  this->AddExitCallback([doc = d.get()]() { doc->dispatch_tokens.pop_back(); });
357 }
358 
359 } // namespace printer
360 } // namespace script
361 } // namespace tvm
362 
363 #endif // TVM_SCRIPT_PRINTER_IR_DOCSIFIER_H_
Managed reference to GlobalInfoNode.
Definition: global_info.h:54
Definition: script_printer.h:155
Runtime primitive data type.
Definition: data_type.h:47
Reference type of DocNode.
Definition: doc.h:87
Reference type of ExprDocNode.
Definition: doc.h:145
Definition: ir_docsifier.h:50
virtual void EnterWithScope()
Method that's called when Frame enters the scope.
Definition: ir_docsifier.h:258
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:264
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, 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:354
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
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(Frame, ObjectRef, FrameNode)
virtual ~Frame()=default
void ExitWithScope()
Method that's called when Frame exits the scope.
Definition: ir_docsifier.h:109
Dynamic dispatch functor based on AccessPath.
Definition: ir_docsifier_functor.h:43
IRDocsifier is the top-level interface in the IR->Doc process.
Definition: ir_docsifier.h:122
void Define(const ObjectRef &obj, const Frame &frame, DocCreator doc_factory)
Define variable by doc factory.
std::unordered_set< std::string > ir_usage
The IR usages for headers printing.
Definition: ir_docsifier.h:158
std::function< ExprDoc()> DocCreator
A function that creates the doc for a variable.
Definition: ir_docsifier.h:125
ExprDoc AddMetadata(const ffi::Any &obj)
Add a TVM object to the metadata section.
void SetCommonPrefix(const ObjectRef &root, ffi::TypedFunction< bool(ObjectRef)> is_var)
Set the common prefix information of variable usage.
std::unordered_map< ffi::String, ffi::Array< ffi::Any > > metadata
Metadata printing.
Definition: ir_docsifier.h:150
std::unordered_map< ObjectRef, VariableInfo, ObjectPtrHash, ObjectPtrEqual > obj2info
Mapping from a var to its info.
Definition: ir_docsifier.h:148
TDoc AsDoc(const Any &obj, const AccessPath &path) const
Transform the input object into TDoc.
Definition: ir_docsifier.h:313
TVM_FFI_DECLARE_OBJECT_INFO_FINAL("script.printer.IRDocsifier", IRDocsifierNode, Object)
ffi::Array< Frame > frames
The stack of frames.
Definition: ir_docsifier.h:139
IdDoc Define(const ObjectRef &obj, const Frame &frame, const ffi::String &name_hint)
Define variable by name.
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:154
PrinterConfig cfg
The configuration of the printer.
Definition: ir_docsifier.h:134
bool IsVarDefined(const ObjectRef &obj) const
Check if a variable exists in the table.
std::unordered_map< const Object *, std::vector< const Object * > > common_prefix
Common prefixes of variable usages.
Definition: ir_docsifier.h:156
static void RegisterReflection()
Definition: ir_docsifier.h:160
std::unordered_map< ffi::String, ffi::Array< GlobalInfo > > global_infos
GlobalInfo printing.
Definition: ir_docsifier.h:152
ffi::Optional< ExprDoc > GetVarDoc(const ObjectRef &obj) const
Get the doc for variable.
static constexpr const bool _type_mutable
Definition: ir_docsifier.h:167
void RemoveVar(const ObjectRef &obj)
Remove the variable defined.
void AddGlobalInfo(const ffi::String &name, const GlobalInfo &ginfo)
Add a GlobalInfo to the global_infos map.
Reference type of IRDocsifierNode.
Definition: ir_docsifier.h:245
static FType & vtable()
The registration table for IRDocsifier.
IRDocsifier(const PrinterConfig &cfg)
Create a IRDocsifier.
TVM_FFI_DEFINE_OBJECT_REF_METHODS_NOTNULLABLE(IRDocsifier, ObjectRef, IRDocsifierNode)
Reference type of IdDocNode.
Definition: doc.h:349
static LiteralDoc Boolean(bool v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent boolean.
Definition: doc.h:285
static LiteralDoc DataType(const runtime::DataType &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition: doc.h:309
static LiteralDoc Device(const DLDevice &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent device.
Definition: doc.h:318
static LiteralDoc Int(int64_t v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent integer.
Definition: doc.h:277
static LiteralDoc Float(double v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent float.
Definition: doc.h:293
static LiteralDoc None(const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent None/null/empty value.
Definition: doc.h:269
static LiteralDoc Str(const ffi::String &v, const ffi::Optional< AccessPath > &p)
Create a LiteralDoc to represent string.
Definition: doc.h:301
The base class of statement doc.
Definition: doc.h:166
IRModule that holds the functions and type definitions.
Definition: repr_printer.h:91
ffi::reflection::AccessPath AccessPath
Definition: doc.h:35
Performance counters for profiling via the PAPI library.
Definition: analyzer.h:37
Definitions and helper macros for IR/AST nodes.
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