Skip to content

Commit db5bfa3

Browse files
joshpolltqchen
authored andcommitted
[Relay][Text Format] Text Printer Refactor and Debug Printing (#2605)
1 parent 259aa46 commit db5bfa3

File tree

10 files changed

+961
-918
lines changed

10 files changed

+961
-918
lines changed

include/tvm/relay/expr.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -551,10 +551,9 @@ inline const TTypeNode* ExprNode::type_as() const {
551551
* additional comment block to an expr.
552552
* \return The text representation.
553553
*/
554-
std::string RelayPrint(
555-
const NodeRef& node,
556-
bool show_meta_data = true,
557-
runtime::TypedPackedFunc<std::string(Expr)> annotate = nullptr);
554+
std::string RelayPrint(const NodeRef& node,
555+
bool show_meta_data = true,
556+
runtime::TypedPackedFunc<std::string(Expr)> annotate = nullptr);
558557
} // namespace relay
559558
} // namespace tvm
560559
#endif // TVM_RELAY_EXPR_H_

python/tvm/relay/_parser.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,9 @@ def make_parser(data):
512512
def fromtext(data, source_name=None):
513513
# type: (str, str) -> Union[expr.Expr, module.Module]
514514
"""Parse a Relay program."""
515+
if data == "":
516+
raise ParseError("Cannot parse the empty string.")
517+
515518
global __source_name_counter__
516519

517520
if source_name is None:

python/tvm/relay/base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def astext(self, show_meta_data=True, annotate=None):
5353
5454
Note
5555
----
56-
The metadata section is necessary to fully parse the text format.
56+
The meta data section is necessary to fully parse the text format.
5757
However, it can contain dumps that are big (e.g constant weights),
5858
so it can be helpful to skip printing the meta data section.
5959

python/tvm/relay/ir_pass.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -905,3 +905,35 @@ def eliminate_common_subexpr(expr, fskip=None):
905905
The output expression.
906906
"""
907907
return _ir_pass.eliminate_common_subexpr(expr, fskip)
908+
909+
910+
def pass_debug_print(ast, show_meta_data=True, annotate=None, gnf=True):
911+
"""
912+
THIS SHOULD BE USED ONLY FOR DEBUGGING, NOT AS AN INTERCHANGE FORMAT!
913+
USE `.astext()` INSTEAD!
914+
915+
A version of the pretty printer intended for debugging passes. Contains
916+
advanced printing options.
917+
918+
Parameters
919+
----------
920+
ast : Union[relay.Expr, relay.Module, relay.Type]
921+
The relay fragment to be turned into text.
922+
923+
show_meta_data : bool
924+
Whether to include meta data section in the text
925+
if there is meta data.
926+
927+
annotate: Optional[relay.Expr->str]
928+
Optional annotate function to provide additional
929+
information in the comment block.
930+
931+
gnf : bool
932+
Whether to print in GNF. If it is disabled, pointers are left implicit.
933+
934+
Returns
935+
-------
936+
text : str
937+
A text representation of `ast`.
938+
"""
939+
return _ir_pass.pass_debug_print(ast, show_meta_data, annotate, gnf)

src/relay/ir/doc.cc

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*!
2+
* Copyright (c) 2019 by Contributors
3+
* \file src/tvm/relay/doc.cc
4+
* \brief Doc ADT used for pretty printing.
5+
* Based on Section 1 of https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf.
6+
*/
7+
#include <memory>
8+
#include <vector>
9+
#include "doc.h"
10+
11+
namespace tvm {
12+
namespace relay {
13+
14+
// Text constructor
15+
DocAtom Text(const std::string& str) {
16+
return std::make_shared<TextNode>(str);
17+
}
18+
19+
// Line constructor
20+
DocAtom Line(int indent = 0) {
21+
return std::make_shared<LineNode>(indent);
22+
}
23+
24+
Doc::Doc(const std::string& str) {
25+
if (str == "\n") {
26+
this->stream_ = {Line()};
27+
} else {
28+
this->stream_ = {Text(str)};
29+
}
30+
}
31+
32+
// DSL function implementations
33+
34+
Doc& Doc::operator<<(const Doc& right) {
35+
assert(this != &right);
36+
this->stream_.insert(this->stream_.end(), right.stream_.begin(), right.stream_.end());
37+
return *this;
38+
}
39+
40+
Doc& Doc::operator<<(const std::string& right) {
41+
return *this << Doc(right);
42+
}
43+
44+
Doc Indent(int indent, const Doc& doc) {
45+
Doc ret;
46+
for (auto atom : doc.stream_) {
47+
if (auto text = std::dynamic_pointer_cast<TextNode>(atom)) {
48+
ret.stream_.push_back(text);
49+
} else if (auto line = std::dynamic_pointer_cast<LineNode>(atom)) {
50+
ret.stream_.push_back(Line(indent + line->indent));
51+
} else {assert(false);}
52+
}
53+
return ret;
54+
}
55+
56+
std::string Doc::str() {
57+
std::ostringstream os;
58+
for (auto atom : this->stream_) {
59+
if (auto text = std::dynamic_pointer_cast<TextNode>(atom)) {
60+
os << text->str;
61+
} else if (auto line = std::dynamic_pointer_cast<LineNode>(atom)) {
62+
os << "\n" << std::string(line->indent, ' ');
63+
} else {assert(false);}
64+
}
65+
return os.str();
66+
}
67+
68+
Doc PrintVec(const std::vector<Doc>& vec, const Doc& sep) {
69+
Doc seq;
70+
if (vec.size() != 0) {
71+
seq = vec[0];
72+
for (size_t i = 1; i < vec.size(); i++) {
73+
seq << sep << vec[i];
74+
}
75+
}
76+
return seq;
77+
}
78+
79+
Doc PrintBool(bool value) {
80+
if (value) {
81+
return Doc("True");
82+
} else {
83+
return Doc("False");
84+
}
85+
}
86+
87+
Doc PrintDType(DataType dtype) {
88+
return Doc(runtime::TVMType2String(Type2TVMType(dtype)));
89+
}
90+
91+
Doc PrintString(const std::string& value) {
92+
// TODO(M.K.): add escape.
93+
Doc doc;
94+
return doc << "\"" << value << "\"";
95+
}
96+
97+
} // namespace relay
98+
} // namespace tvm

src/relay/ir/doc.h

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*!
2+
* Copyright (c) 2019 by Contributors
3+
* \file tvm/relay/doc.h
4+
* \brief Doc ADT used for pretty printing.
5+
* Based on Section 1 of
6+
* https://homepages.inf.ed.ac.uk/wadler/papers/prettier/prettier.pdf, but with
7+
* a vector instead of an implicitly linked list.
8+
*/
9+
#ifndef TVM_RELAY_IR_DOC_H_
10+
#define TVM_RELAY_IR_DOC_H_
11+
12+
#include <tvm/relay/expr.h>
13+
#include <memory>
14+
#include <string>
15+
#include <vector>
16+
17+
namespace tvm {
18+
namespace relay {
19+
20+
// Doc Atom ADT
21+
struct DocAtomNode {
22+
virtual ~DocAtomNode() = default;
23+
};
24+
25+
using DocAtom = std::shared_ptr<DocAtomNode>;
26+
27+
struct TextNode : DocAtomNode {
28+
std::string str;
29+
30+
explicit TextNode(const std::string& str) : str(str) {}
31+
};
32+
33+
struct LineNode : DocAtomNode {
34+
int indent;
35+
36+
explicit LineNode(int indent) : indent(indent) {}
37+
};
38+
39+
// Doc is a stream-like interface
40+
class Doc {
41+
public:
42+
Doc() {}
43+
explicit Doc(const std::string& str);
44+
45+
// Append right to this.
46+
Doc& operator<<(const Doc& right);
47+
// Like above, but automatically lifts string to a Doc.
48+
Doc& operator<<(const std::string& right);
49+
// Like above, but converts right to a string first.
50+
template<typename T>
51+
Doc& operator<<(const T& right) {
52+
std::ostringstream os;
53+
os << right;
54+
return *this << os.str();
55+
}
56+
57+
// Indent a doc stream.
58+
friend Doc Indent(int indent, const Doc& doc);
59+
60+
// Wadler's `layout`
61+
std::string str();
62+
63+
private:
64+
std::vector<DocAtom> stream_;
65+
};
66+
67+
// DSL functions
68+
69+
// Render vectors of docs with a separator. e.g. PrintVec([1, 2, 3], f) -> 1f2f3
70+
Doc PrintVec(const std::vector<Doc>& vec, const Doc& sep = Doc(", "));
71+
// Print a constant bool value.
72+
Doc PrintBool(bool value);
73+
// Print a data type.
74+
Doc PrintDType(DataType dtype);
75+
// Print a string.
76+
Doc PrintString(const std::string& value);
77+
/*!
78+
* \brief special method to print out const scalar
79+
* \param dtype The data type
80+
* \param data The pointer to hold the data.
81+
*/
82+
template<typename T>
83+
Doc PrintConstScalar(DataType dtype, const T* data) {
84+
std::ostringstream os;
85+
if (dtype == Int(32)) {
86+
os << data[0];
87+
} else if (dtype == Float(32)) {
88+
os << data[0] << 'f';
89+
} else if (dtype == Bool()) {
90+
return PrintBool(data[0] != 0);
91+
} else {
92+
os << dtype << "(" << data[0] << ")";
93+
}
94+
return Doc(os.str());
95+
}
96+
97+
} // namespace relay
98+
} // namespace tvm
99+
#endif // TVM_RELAY_IR_DOC_H_

0 commit comments

Comments
 (0)